@mcptoolshop/venvkit 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +249 -0
- package/dist/doctorLite.d.ts +75 -0
- package/dist/doctorLite.d.ts.map +1 -0
- package/dist/doctorLite.js +705 -0
- package/dist/doctorLite.js.map +1 -0
- package/dist/doctorLite.test.d.ts +2 -0
- package/dist/doctorLite.test.d.ts.map +1 -0
- package/dist/doctorLite.test.js +268 -0
- package/dist/doctorLite.test.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/integration.test.d.ts +2 -0
- package/dist/integration.test.d.ts.map +1 -0
- package/dist/integration.test.js +245 -0
- package/dist/integration.test.js.map +1 -0
- package/dist/mapRender.d.ts +105 -0
- package/dist/mapRender.d.ts.map +1 -0
- package/dist/mapRender.js +718 -0
- package/dist/mapRender.js.map +1 -0
- package/dist/mapRender.test.d.ts +2 -0
- package/dist/mapRender.test.d.ts.map +1 -0
- package/dist/mapRender.test.js +571 -0
- package/dist/mapRender.test.js.map +1 -0
- package/dist/map_cli.d.ts +3 -0
- package/dist/map_cli.d.ts.map +1 -0
- package/dist/map_cli.js +278 -0
- package/dist/map_cli.js.map +1 -0
- package/dist/map_cli.test.d.ts +2 -0
- package/dist/map_cli.test.d.ts.map +1 -0
- package/dist/map_cli.test.js +276 -0
- package/dist/map_cli.test.js.map +1 -0
- package/dist/runLog.d.ts +71 -0
- package/dist/runLog.d.ts.map +1 -0
- package/dist/runLog.js +98 -0
- package/dist/runLog.js.map +1 -0
- package/dist/runLog.test.d.ts +2 -0
- package/dist/runLog.test.d.ts.map +1 -0
- package/dist/runLog.test.js +327 -0
- package/dist/runLog.test.js.map +1 -0
- package/dist/scanEnvPaths.d.ts +18 -0
- package/dist/scanEnvPaths.d.ts.map +1 -0
- package/dist/scanEnvPaths.js +174 -0
- package/dist/scanEnvPaths.js.map +1 -0
- package/dist/scanEnvPaths.test.d.ts +2 -0
- package/dist/scanEnvPaths.test.d.ts.map +1 -0
- package/dist/scanEnvPaths.test.js +250 -0
- package/dist/scanEnvPaths.test.js.map +1 -0
- package/dist/taskCluster.d.ts +62 -0
- package/dist/taskCluster.d.ts.map +1 -0
- package/dist/taskCluster.js +180 -0
- package/dist/taskCluster.js.map +1 -0
- package/dist/taskCluster.test.d.ts +2 -0
- package/dist/taskCluster.test.d.ts.map +1 -0
- package/dist/taskCluster.test.js +375 -0
- package/dist/taskCluster.test.js.map +1 -0
- package/dist/vitest.config.d.ts +3 -0
- package/dist/vitest.config.d.ts.map +1 -0
- package/dist/vitest.config.js +8 -0
- package/dist/vitest.config.js.map +1 -0
- package/package.json +58 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 mcp-tool-shop
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
# venvkit
|
|
2
|
+
|
|
3
|
+
[](https://github.com/mcp-tool-shop/venvkit/actions/workflows/ci.yml)
|
|
4
|
+
[](https://opensource.org/licenses/MIT)
|
|
5
|
+
|
|
6
|
+
**Python virtual environment diagnostic toolkit for Windows ML workflows.**
|
|
7
|
+
|
|
8
|
+
Scans your system for Python environments, diagnoses health issues (SSL, DLLs, ABI mismatches, path leakage), tracks task execution history, detects flaky tasks, and renders an ecosystem map.
|
|
9
|
+
|
|
10
|
+
## 30-Second Quickstart
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
git clone https://github.com/mcp-tool-shop/venvkit && cd venvkit
|
|
14
|
+
npm install && npm run build
|
|
15
|
+
node dist/map_cli.js --root C:\projects --httpsProbe
|
|
16
|
+
# Open .venvkit/venv-map.html in your browser
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Features
|
|
20
|
+
|
|
21
|
+
- **doctorLite** - Fast health check for any Python interpreter
|
|
22
|
+
- SSL/TLS verification
|
|
23
|
+
- DLL load failures (common with PyTorch/CUDA)
|
|
24
|
+
- ABI mismatches (ARM vs x86)
|
|
25
|
+
- pip sanity checks
|
|
26
|
+
- User-site and PYTHONPATH leakage detection
|
|
27
|
+
|
|
28
|
+
- **scanEnvPaths** - Discover all Python environments on your system
|
|
29
|
+
- Finds venvs, conda envs, pyenv versions, base interpreters
|
|
30
|
+
- Configurable depth and filtering
|
|
31
|
+
|
|
32
|
+
- **mapRender** - Visualize your Python ecosystem
|
|
33
|
+
- Graph JSON output for programmatic use
|
|
34
|
+
- Mermaid diagrams for documentation
|
|
35
|
+
- Base interpreter grouping with blast radius analysis
|
|
36
|
+
- Task routing visualization
|
|
37
|
+
|
|
38
|
+
- **runLog** - Track task execution history
|
|
39
|
+
- Append-only JSONL format
|
|
40
|
+
- Records which env ran what task
|
|
41
|
+
- Captures success/failure with error classification
|
|
42
|
+
|
|
43
|
+
- **taskCluster** - Aggregate task runs by signature
|
|
44
|
+
- Flaky task detection (inconsistent pass/fail)
|
|
45
|
+
- Environment-dependent flake detection
|
|
46
|
+
- Failure hotspot identification
|
|
47
|
+
- Contagion analysis (shared root causes)
|
|
48
|
+
|
|
49
|
+
## Installation
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
npm install
|
|
53
|
+
npm run build
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## CLI Usage
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
# Scan current directory and generate ecosystem map
|
|
60
|
+
node dist/map_cli.js
|
|
61
|
+
|
|
62
|
+
# Scan specific directories
|
|
63
|
+
node dist/map_cli.js --root C:\projects --root D:\ml-experiments
|
|
64
|
+
|
|
65
|
+
# Include task run history
|
|
66
|
+
node dist/map_cli.js --runlog .venvkit/runs.jsonl
|
|
67
|
+
|
|
68
|
+
# Output options
|
|
69
|
+
node dist/map_cli.js --out ./output --minScore 50 --strict --httpsProbe
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### CLI Options
|
|
73
|
+
|
|
74
|
+
| Flag | Description |
|
|
75
|
+
|------|-------------|
|
|
76
|
+
| `--root, -r` | Directory to scan (can specify multiple) |
|
|
77
|
+
| `--out` | Output directory (default: `.venvkit`) |
|
|
78
|
+
| `--maxDepth` | Max directory depth to scan (default: 5) |
|
|
79
|
+
| `--strict` | Enable strict mode checks |
|
|
80
|
+
| `--httpsProbe` | Test HTTPS connectivity |
|
|
81
|
+
| `--minScore` | Filter envs below this health score |
|
|
82
|
+
| `--concurrency` | Parallel checks (default: CPU count) |
|
|
83
|
+
| `--runlog` | Path to task run log (JSONL) |
|
|
84
|
+
| `--no-tasks` | Skip task visualization |
|
|
85
|
+
|
|
86
|
+
### Outputs
|
|
87
|
+
|
|
88
|
+
| File | Description |
|
|
89
|
+
|------|-------------|
|
|
90
|
+
| `venv-map.json` | Full graph data (nodes, edges, summary) |
|
|
91
|
+
| `venv-map.mmd` | Mermaid diagram source |
|
|
92
|
+
| `venv-map.html` | Interactive viewer |
|
|
93
|
+
| `reports.json` | Raw doctorLite reports |
|
|
94
|
+
| `insights.json` | Actionable recommendations |
|
|
95
|
+
|
|
96
|
+
## Programmatic Usage
|
|
97
|
+
|
|
98
|
+
```typescript
|
|
99
|
+
import { doctorLite, scanEnvPaths, mapRender, readRunLog } from 'venvkit';
|
|
100
|
+
|
|
101
|
+
// Check a specific Python
|
|
102
|
+
const report = await doctorLite({
|
|
103
|
+
pythonPath: 'C:\\project\\.venv\\Scripts\\python.exe',
|
|
104
|
+
requiredModules: ['torch', 'transformers'],
|
|
105
|
+
httpsProbe: true,
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
console.log(report.status); // 'good' | 'warn' | 'bad'
|
|
109
|
+
console.log(report.score); // 0-100
|
|
110
|
+
console.log(report.findings); // Array of issues
|
|
111
|
+
|
|
112
|
+
// Scan for all Python environments
|
|
113
|
+
const scan = await scanEnvPaths({
|
|
114
|
+
roots: ['C:\\projects'],
|
|
115
|
+
maxDepth: 5,
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
// Run doctorLite on all found environments
|
|
119
|
+
const reports = await Promise.all(
|
|
120
|
+
scan.pythonPaths.map(p => doctorLite({ pythonPath: p }))
|
|
121
|
+
);
|
|
122
|
+
|
|
123
|
+
// Load task execution history
|
|
124
|
+
const runs = await readRunLog('.venvkit/runs.jsonl');
|
|
125
|
+
|
|
126
|
+
// Generate ecosystem visualization
|
|
127
|
+
const { graph, mermaid, insights } = mapRender(reports, runs, {
|
|
128
|
+
taskMode: 'clustered', // 'none' | 'runs' | 'clustered'
|
|
129
|
+
includeHotEdgeLabels: true,
|
|
130
|
+
});
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## Run Log Schema
|
|
134
|
+
|
|
135
|
+
Track task executions by appending events to a JSONL file:
|
|
136
|
+
|
|
137
|
+
```typescript
|
|
138
|
+
import { appendRunLog, newRunId } from 'venvkit';
|
|
139
|
+
|
|
140
|
+
await appendRunLog('.venvkit/runs.jsonl', {
|
|
141
|
+
version: '1.0',
|
|
142
|
+
runId: newRunId(),
|
|
143
|
+
at: new Date().toISOString(),
|
|
144
|
+
task: {
|
|
145
|
+
name: 'train',
|
|
146
|
+
command: 'python train.py --epochs 10',
|
|
147
|
+
requirements: { packages: ['torch', 'transformers'] },
|
|
148
|
+
},
|
|
149
|
+
selected: {
|
|
150
|
+
pythonPath: 'C:\\project\\.venv\\Scripts\\python.exe',
|
|
151
|
+
score: 95,
|
|
152
|
+
status: 'good',
|
|
153
|
+
},
|
|
154
|
+
outcome: {
|
|
155
|
+
ok: true,
|
|
156
|
+
exitCode: 0,
|
|
157
|
+
durationMs: 45000,
|
|
158
|
+
},
|
|
159
|
+
});
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
## Task Clustering
|
|
163
|
+
|
|
164
|
+
When you have many task runs, venvkit clusters them by signature:
|
|
165
|
+
|
|
166
|
+
```typescript
|
|
167
|
+
import { clusterRuns, isFlaky, getFailingEnvs } from 'venvkit';
|
|
168
|
+
|
|
169
|
+
const clusters = clusterRuns(runs);
|
|
170
|
+
|
|
171
|
+
for (const c of clusters) {
|
|
172
|
+
console.log(`${c.sig.name}: ${c.ok}/${c.runs} (${(c.successRate * 100).toFixed(0)}%)`);
|
|
173
|
+
|
|
174
|
+
if (isFlaky(c)) {
|
|
175
|
+
console.log(` WARNING: Flaky task!`);
|
|
176
|
+
const badEnvs = getFailingEnvs(c, 3);
|
|
177
|
+
console.log(` Failing most on: ${badEnvs.map(e => e.pythonPath).join(', ')}`);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
## Graph Schema
|
|
183
|
+
|
|
184
|
+
The `mapRender` output follows a stable JSON schema:
|
|
185
|
+
|
|
186
|
+
```typescript
|
|
187
|
+
type GraphJSONv1 = {
|
|
188
|
+
version: '1.0';
|
|
189
|
+
generatedAt: string;
|
|
190
|
+
host: { os: string; arch: string; hostname: string };
|
|
191
|
+
summary: {
|
|
192
|
+
envCount: number;
|
|
193
|
+
baseCount: number;
|
|
194
|
+
taskCount: number;
|
|
195
|
+
healthy: number;
|
|
196
|
+
warning: number;
|
|
197
|
+
broken: number;
|
|
198
|
+
runsPassed: number;
|
|
199
|
+
runsFailed: number;
|
|
200
|
+
topIssues: Array<{ code: string; count: number; hint: string }>;
|
|
201
|
+
};
|
|
202
|
+
nodes: GraphNode[];
|
|
203
|
+
edges: GraphEdge[];
|
|
204
|
+
};
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
### Node Types
|
|
208
|
+
|
|
209
|
+
| Type | Description |
|
|
210
|
+
|------|-------------|
|
|
211
|
+
| `base` | Base Python interpreter (e.g., `C:\Python311`) |
|
|
212
|
+
| `venv` | Virtual environment |
|
|
213
|
+
| `task` | Task signature (clustered runs) |
|
|
214
|
+
|
|
215
|
+
### Edge Types
|
|
216
|
+
|
|
217
|
+
| Type | Description |
|
|
218
|
+
|------|-------------|
|
|
219
|
+
| `USES_BASE` | venv → base relationship |
|
|
220
|
+
| `ROUTES_TASK_TO` | task → env routing |
|
|
221
|
+
| `FAILED_RUN` | task → env failure (dashed in Mermaid) |
|
|
222
|
+
|
|
223
|
+
## Finding Codes
|
|
224
|
+
|
|
225
|
+
| Code | Severity | Description |
|
|
226
|
+
|------|----------|-------------|
|
|
227
|
+
| `SSL_BROKEN` | bad | SSL module fails to import |
|
|
228
|
+
| `CERT_STORE_FAIL` | warn | HTTPS certificate verification fails |
|
|
229
|
+
| `DLL_LOAD_FAIL` | bad | Native extension DLL loading fails |
|
|
230
|
+
| `ABI_MISMATCH` | bad | Binary incompatibility (ARM/x86) |
|
|
231
|
+
| `PIP_MISSING` | warn | pip not available |
|
|
232
|
+
| `PIP_CHECK_FAIL` | warn | Dependency conflicts detected |
|
|
233
|
+
| `USER_SITE_LEAK` | warn | User site-packages enabled in venv |
|
|
234
|
+
| `PYTHONPATH_INJECTED` | warn | PYTHONPATH environment variable set |
|
|
235
|
+
| `ARCH_MISMATCH` | bad | 32-bit Python when 64-bit required |
|
|
236
|
+
| `PYVENV_CFG_INVALID` | warn | Broken or missing pyvenv.cfg |
|
|
237
|
+
|
|
238
|
+
## Development
|
|
239
|
+
|
|
240
|
+
```bash
|
|
241
|
+
npm install
|
|
242
|
+
npm run typecheck # Type check
|
|
243
|
+
npm run test # Run tests
|
|
244
|
+
npm run build # Build to dist/
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
## License
|
|
248
|
+
|
|
249
|
+
MIT
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
export type Severity = "info" | "warn" | "bad";
|
|
2
|
+
export type HealthStatus = "good" | "warn" | "bad" | "unknown";
|
|
3
|
+
export type FindingCode = "PYTHON_EXEC_MISSING" | "NOT_A_VENV" | "ARCH_MISMATCH" | "PIP_MISSING" | "PIP_POINTS_TO_OTHER_PYTHON" | "PYTHONPATH_INJECTED" | "USER_SITE_ENABLED" | "USER_SITE_LEAK" | "PIP_CHECK_FAIL" | "MULTI_VERSION_ON_PATH" | "RESOLVER_CONFLICT_HINT" | "OUTDATED_INSTALL_TOOLING" | "IMPORT_FAIL" | "DLL_LOAD_FAIL" | "ABI_MISMATCH" | "SSL_BROKEN" | "CERT_STORE_FAIL" | "SUBPROCESS_BROKEN" | "PYVENV_CFG_INVALID";
|
|
4
|
+
export type Finding = {
|
|
5
|
+
code: FindingCode;
|
|
6
|
+
severity: Severity;
|
|
7
|
+
penalty: number;
|
|
8
|
+
what: string;
|
|
9
|
+
why: string;
|
|
10
|
+
fix: Array<{
|
|
11
|
+
title: string;
|
|
12
|
+
steps: string[];
|
|
13
|
+
}>;
|
|
14
|
+
evidence?: Record<string, unknown>;
|
|
15
|
+
};
|
|
16
|
+
export type RunResult = {
|
|
17
|
+
ok: boolean;
|
|
18
|
+
exitCode: number | null;
|
|
19
|
+
stdout: string;
|
|
20
|
+
stderr: string;
|
|
21
|
+
timedOut: boolean;
|
|
22
|
+
};
|
|
23
|
+
export type CmdRunner = (cmd: string, args: string[], opts: {
|
|
24
|
+
env?: NodeJS.ProcessEnv;
|
|
25
|
+
timeoutMs: number;
|
|
26
|
+
}) => Promise<RunResult>;
|
|
27
|
+
export type DoctorLiteOptions = {
|
|
28
|
+
/** Python executable path (venv python or base python). Required. */
|
|
29
|
+
pythonPath: string;
|
|
30
|
+
/** Modules to import-test (task required caps). */
|
|
31
|
+
requiredModules?: string[];
|
|
32
|
+
/** If true, also do a HTTPS probe to pypi.org (can fail in corp MITM; still useful). */
|
|
33
|
+
httpsProbe?: boolean;
|
|
34
|
+
/** If task requires 64-bit python, set true. If unknown, leave undefined. */
|
|
35
|
+
requireX64?: boolean;
|
|
36
|
+
/** Timeout per subprocess (ms). */
|
|
37
|
+
timeoutMs?: number;
|
|
38
|
+
/** If true, run heavier checks (pip check, multi-version scan). */
|
|
39
|
+
strict?: boolean;
|
|
40
|
+
/** Override environment variables passed to python. */
|
|
41
|
+
env?: Record<string, string | undefined>;
|
|
42
|
+
};
|
|
43
|
+
export type DoctorLiteReport = {
|
|
44
|
+
pythonPath: string;
|
|
45
|
+
ranAt: string;
|
|
46
|
+
status: HealthStatus;
|
|
47
|
+
score: number;
|
|
48
|
+
summary: string;
|
|
49
|
+
facts?: FactsResult;
|
|
50
|
+
findings: Finding[];
|
|
51
|
+
};
|
|
52
|
+
type FactsResult = {
|
|
53
|
+
version: string;
|
|
54
|
+
version_info: number[];
|
|
55
|
+
executable: string;
|
|
56
|
+
prefix: string;
|
|
57
|
+
base_prefix: string | null;
|
|
58
|
+
bits: number;
|
|
59
|
+
machine: string;
|
|
60
|
+
os: string;
|
|
61
|
+
py_path: string[];
|
|
62
|
+
enable_user_site: boolean | null;
|
|
63
|
+
user_site: string;
|
|
64
|
+
};
|
|
65
|
+
/**
|
|
66
|
+
* Run a subprocess with timeout, capturing stdout/stderr.
|
|
67
|
+
*/
|
|
68
|
+
export declare function runCmd(cmd: string, args: string[], opts: {
|
|
69
|
+
env?: NodeJS.ProcessEnv;
|
|
70
|
+
timeoutMs: number;
|
|
71
|
+
}): Promise<RunResult>;
|
|
72
|
+
export declare function doctorLite(opts: DoctorLiteOptions, runner?: CmdRunner): Promise<DoctorLiteReport>;
|
|
73
|
+
export declare function envIdFromPythonPath(pythonPath: string): string;
|
|
74
|
+
export {};
|
|
75
|
+
//# sourceMappingURL=doctorLite.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doctorLite.d.ts","sourceRoot":"","sources":["../doctorLite.ts"],"names":[],"mappings":"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"}
|