tzero-mcp 10.7.0 → 10.7.1
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/bin/tzero-mcp.js +9 -16
- package/bin/tzero.js +9 -16
- package/index.js +7 -2
- package/package.json +2 -1
- package/src/addmcp.py +1194 -0
- package/src/main.py +60 -0
- package/src/siber_akademi_icon.py +77 -0
- package/src/tzero/jarvis/semantic_compressor.py +373 -0
- package/src/tzero.py +58 -0
- package/src/tzero_benchmark.py +475 -0
- package/src/tzero_bridge.py +362 -0
- package/src/tzero_ci.py +153 -0
- package/src/tzero_commit.py +192 -0
- package/src/tzero_cost.py +163 -0
- package/src/tzero_dashboard.py +1448 -0
- package/src/tzero_deps.py +287 -0
- package/src/tzero_drift.py +208 -0
- package/src/tzero_explain.py +240 -0
- package/src/tzero_features.py +3022 -0
- package/src/tzero_fix.py +228 -0
- package/src/tzero_fixer/__init__.py +63 -0
- package/src/tzero_fixer/amalgamation.py +334 -0
- package/src/tzero_fixer/ast_syntax_healer.py +464 -0
- package/src/tzero_fixer/ast_type_modernizer.py +288 -0
- package/src/tzero_fixer/async_io_modernizer.py +127 -0
- package/src/tzero_fixer/automated_regression_suite.py +600 -0
- package/src/tzero_fixer/benchmarks_and_diagnostics.py +174 -0
- package/src/tzero_fixer/ci_cd_self_healing_gate.py +246 -0
- package/src/tzero_fixer/code_duplicity_and_refactorer.py +151 -0
- package/src/tzero_fixer/code_smells_healer.py +260 -0
- package/src/tzero_fixer/cwe_remediator.py +171 -0
- package/src/tzero_fixer/dead_code_eliminator.py +150 -0
- package/src/tzero_fixer/dependency_vulnerability_auditor.py +309 -0
- package/src/tzero_fixer/git_advanced_surgeon.py +280 -0
- package/src/tzero_fixer/hardware_and_disk_doctor.py +325 -0
- package/src/tzero_fixer/import_graph_healer.py +412 -0
- package/src/tzero_fixer/interactive_tui.py +91 -0
- package/src/tzero_fixer/knowledge_base.py +295 -0
- package/src/tzero_fixer/knowledge_base_extended.py +940 -0
- package/src/tzero_fixer/linters_and_static_analyzer.py +307 -0
- package/src/tzero_fixer/mcp_server.py +447 -0
- package/src/tzero_fixer/models.py +385 -0
- package/src/tzero_fixer/orchestrator.py +375 -0
- package/src/tzero_fixer/os_doctor.py +502 -0
- package/src/tzero_fixer/packaging_abi_surgeon.py +323 -0
- package/src/tzero_fixer/pc_fixer_doctor.py +599 -0
- package/src/tzero_fixer/performance_and_memory_profiler.py +274 -0
- package/src/tzero_fixer/polyglot_ast_parsers.py +313 -0
- package/src/tzero_fixer/polyglot_build_healer.py +364 -0
- package/src/tzero_fixer/polyglot_config_healer.py +318 -0
- package/src/tzero_fixer/polyglot_doctor.py +372 -0
- package/src/tzero_fixer/polyglot_linters.py +619 -0
- package/src/tzero_fixer/polyglot_schema_validator.py +305 -0
- package/src/tzero_fixer/security_cwe_database.py +444 -0
- package/src/tzero_fixer/security_deep_rules.py +114 -0
- package/src/tzero_fixer/security_rules_catalog.py +110 -0
- package/src/tzero_fixer/security_zero_leak.py +326 -0
- package/src/tzero_fixer/smart_patch_recommender.py +223 -0
- package/src/tzero_fixer/synthetic_workspace_generator.py +220 -0
- package/src/tzero_fixer/system_diagnostics_extended.py +493 -0
- package/src/tzero_fixer/system_repair_recipes.py +447 -0
- package/src/tzero_fixer/venv_doctor.py +309 -0
- package/src/tzero_gateway.py +885 -0
- package/src/tzero_guard.py +243 -0
- package/src/tzero_infra.py +274 -0
- package/src/tzero_jarvis/__init__.py +124 -0
- package/src/tzero_jarvis/causal_graph.py +310 -0
- package/src/tzero_jarvis/graph_visualizer.py +395 -0
- package/src/tzero_jarvis/hybrid_search.py +214 -0
- package/src/tzero_jarvis/latent_press.py +137 -0
- package/src/tzero_jarvis/memory_consolidation.py +212 -0
- package/src/tzero_jarvis/minhash_lsh.py +184 -0
- package/src/tzero_jarvis/orchestrator.py +335 -0
- package/src/tzero_jarvis/self_healing.py +308 -0
- package/src/tzero_jarvis/semantic_compressor.py +887 -0
- package/src/tzero_jarvis/swarm.py +261 -0
- package/src/tzero_jarvis/swarm_bft.py +144 -0
- package/src/tzero_jarvis/workspace_orchestrator.py +1167 -0
- package/src/tzero_jarvis/zero_key_router.py +173 -0
- package/src/tzero_mcp.py +4858 -0
- package/src/tzero_neural_cortex.py +1425 -0
- package/src/tzero_packer.py +370 -0
- package/src/tzero_patch.py +624 -0
- package/src/tzero_pc_fixer.py +12657 -0
- package/src/tzero_pipe.py +95 -0
- package/src/tzero_polyglot.py +422 -0
- package/src/tzero_reachability.py +272 -0
- package/src/tzero_replay.py +141 -0
- package/src/tzero_security.py +570 -0
- package/src/tzero_snapshot.py +258 -0
- package/src/tzero_stubs.py +313 -0
- package/src/tzero_superdesign.py +774 -0
- package/src/tzero_sync.py +241 -0
- package/src/tzero_task_benchmark.py +363 -0
- package/src/tzero_tui.py +244 -0
- package/src/tzero_v3.py +9435 -0
|
@@ -0,0 +1,493 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
T-Zero PC-Fixer: Extended System Diagnostics & Deep OS Inspection
|
|
4
|
+
================================================================
|
|
5
|
+
Enterprise-grade, zero-dependency operating system diagnostics engine.
|
|
6
|
+
Provides deep cross-platform diagnostics for:
|
|
7
|
+
- Disk storage health, mount partition thresholds, inode pressure, temp exhaustion
|
|
8
|
+
- Network port conflicts, listening dev servers, socket accumulation
|
|
9
|
+
- Memory pressure, swap/pagefile sizing, cache allocation
|
|
10
|
+
- Zombie processes, orphaned compiler/toolchain locks, runaway dev servers
|
|
11
|
+
- Platform-specific registry policies (Windows LongPaths, DeveloperMode, ExecutionPolicy)
|
|
12
|
+
- POSIX filesystem permissions (SSH keys, sticky bits, executable bits)
|
|
13
|
+
- Package manager locks and stale build artifact accumulation
|
|
14
|
+
|
|
15
|
+
Author: Siber Akademi T-Zero R&D Team
|
|
16
|
+
License: MIT (100% Free, Local Offline, Zero-Leak)
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
from __future__ import annotations
|
|
20
|
+
|
|
21
|
+
import os
|
|
22
|
+
import sys
|
|
23
|
+
import shutil
|
|
24
|
+
import subprocess
|
|
25
|
+
import socket
|
|
26
|
+
import platform
|
|
27
|
+
import glob
|
|
28
|
+
import re
|
|
29
|
+
import tempfile
|
|
30
|
+
from typing import Dict, List, Optional, Tuple, Any, Set
|
|
31
|
+
from dataclasses import dataclass, field
|
|
32
|
+
from pathlib import Path
|
|
33
|
+
|
|
34
|
+
from tzero_fixer.models import (
|
|
35
|
+
DiagnosticCategory,
|
|
36
|
+
DiagnosticIssue,
|
|
37
|
+
|
|
38
|
+
SeverityLevel,
|
|
39
|
+
SystemPlatform,
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
@dataclass
|
|
44
|
+
class DiskPartitionHealth:
|
|
45
|
+
mount_point: str
|
|
46
|
+
total_bytes: int
|
|
47
|
+
used_bytes: int
|
|
48
|
+
free_bytes: int
|
|
49
|
+
percent_used: float
|
|
50
|
+
is_critical: bool
|
|
51
|
+
is_warning: bool
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
@dataclass
|
|
55
|
+
class NetworkPortStatus:
|
|
56
|
+
port: int
|
|
57
|
+
service_hint: str
|
|
58
|
+
is_open: bool
|
|
59
|
+
pid: Optional[int] = None
|
|
60
|
+
process_name: Optional[str] = None
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
@dataclass
|
|
64
|
+
class ExtendedDiagnosticSummary:
|
|
65
|
+
platform: SystemPlatform
|
|
66
|
+
disk_health: List[DiskPartitionHealth] = field(default_factory=list)
|
|
67
|
+
port_conflicts: List[NetworkPortStatus] = field(default_factory=list)
|
|
68
|
+
memory_warning: bool = False
|
|
69
|
+
swap_warning: bool = False
|
|
70
|
+
temp_dir_exhaustion: bool = False
|
|
71
|
+
zombie_process_count: int = 0
|
|
72
|
+
stale_locks_detected: List[str] = field(default_factory=list)
|
|
73
|
+
permission_issues: List[str] = field(default_factory=list)
|
|
74
|
+
registry_recommendations: List[str] = field(default_factory=list)
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
class ExtendedSystemDiagnostics:
|
|
78
|
+
"""
|
|
79
|
+
Exhaustive low-overhead system inspection engine for software engineering workstations.
|
|
80
|
+
Strictly reads OS signals without modifying system state or making external API calls.
|
|
81
|
+
"""
|
|
82
|
+
|
|
83
|
+
COMMON_DEV_PORTS: Dict[int, str] = {
|
|
84
|
+
3000: "Next.js / React Dev Server / Ruby on Rails",
|
|
85
|
+
3001: "Secondary Node.js Dev Server",
|
|
86
|
+
4000: "Hexo / Jekyll / GraphQL Gateway",
|
|
87
|
+
4200: "Angular CLI Dev Server",
|
|
88
|
+
5000: "Flask / ASP.NET Core Dev Server",
|
|
89
|
+
5173: "Vite Dev Server (Vue / React / Svelte)",
|
|
90
|
+
8000: "Django / FastAPI / Uvicorn Server",
|
|
91
|
+
8080: "Tomcat / Spring Boot / Vue CLI fallback",
|
|
92
|
+
8888: "Jupyter Notebook / JupyterLab Server",
|
|
93
|
+
9000: "PHP-FPM / MinIO / SonarQube",
|
|
94
|
+
5432: "PostgreSQL Database Engine",
|
|
95
|
+
3306: "MySQL / MariaDB Database Engine",
|
|
96
|
+
27017: "MongoDB Community Server",
|
|
97
|
+
6379: "Redis In-Memory Key-Value Store",
|
|
98
|
+
9200: "Elasticsearch / OpenSearch REST API",
|
|
99
|
+
11434: "Ollama Local LLM Inference Server",
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
def __init__(self, workspace_path: Optional[str] = None):
|
|
103
|
+
self.workspace_path = Path(workspace_path or os.getcwd()).resolve()
|
|
104
|
+
self.platform = self._detect_platform()
|
|
105
|
+
|
|
106
|
+
def _detect_platform(self) -> SystemPlatform:
|
|
107
|
+
sys_name = platform.system().lower()
|
|
108
|
+
if "windows" in sys_name:
|
|
109
|
+
return SystemPlatform.WINDOWS
|
|
110
|
+
elif "darwin" in sys_name:
|
|
111
|
+
return SystemPlatform.MACOS
|
|
112
|
+
elif "linux" in sys_name:
|
|
113
|
+
return SystemPlatform.LINUX
|
|
114
|
+
return SystemPlatform.UNKNOWN
|
|
115
|
+
|
|
116
|
+
# -------------------------------------------------------------------------
|
|
117
|
+
# 1. Storage & Filesystem Health
|
|
118
|
+
# -------------------------------------------------------------------------
|
|
119
|
+
def inspect_disk_health(self) -> Tuple[List[DiskPartitionHealth], List[DiagnosticIssue]]:
|
|
120
|
+
"""
|
|
121
|
+
Scans mount points and current working drive for disk space thresholds.
|
|
122
|
+
Emits warning (>85% used) and critical (>95% used or <2GB free) issues.
|
|
123
|
+
"""
|
|
124
|
+
partitions: List[DiskPartitionHealth] = []
|
|
125
|
+
issues: List[DiagnosticIssue] = []
|
|
126
|
+
|
|
127
|
+
mounts_to_check: Set[str] = set()
|
|
128
|
+
# Current workspace drive
|
|
129
|
+
try:
|
|
130
|
+
mounts_to_check.add(str(self.workspace_path.anchor or "/"))
|
|
131
|
+
except Exception:
|
|
132
|
+
mounts_to_check.add("/")
|
|
133
|
+
|
|
134
|
+
# Temp directory drive
|
|
135
|
+
try:
|
|
136
|
+
temp_path = Path(tempfile.gettempdir())
|
|
137
|
+
mounts_to_check.add(str(temp_path.anchor or "/"))
|
|
138
|
+
except Exception:
|
|
139
|
+
pass
|
|
140
|
+
|
|
141
|
+
if self.platform == SystemPlatform.WINDOWS:
|
|
142
|
+
# Check common Windows drive letters (C, D, E)
|
|
143
|
+
for drive in ["C:\\", "D:\\"]:
|
|
144
|
+
if os.path.exists(drive):
|
|
145
|
+
mounts_to_check.add(drive)
|
|
146
|
+
else:
|
|
147
|
+
mounts_to_check.add("/")
|
|
148
|
+
|
|
149
|
+
for mount in sorted(mounts_to_check):
|
|
150
|
+
try:
|
|
151
|
+
usage = shutil.disk_usage(mount)
|
|
152
|
+
total = usage.total
|
|
153
|
+
used = usage.used
|
|
154
|
+
free = usage.free
|
|
155
|
+
pct = (used / total) * 100.0 if total > 0 else 0.0
|
|
156
|
+
|
|
157
|
+
is_critical = pct >= 95.0 or (free < 2 * 1024 * 1024 * 1024)
|
|
158
|
+
is_warning = pct >= 85.0 and not is_critical
|
|
159
|
+
|
|
160
|
+
health = DiskPartitionHealth(
|
|
161
|
+
mount_point=mount,
|
|
162
|
+
total_bytes=total,
|
|
163
|
+
used_bytes=used,
|
|
164
|
+
free_bytes=free,
|
|
165
|
+
percent_used=pct,
|
|
166
|
+
is_critical=is_critical,
|
|
167
|
+
is_warning=is_warning,
|
|
168
|
+
)
|
|
169
|
+
partitions.append(health)
|
|
170
|
+
|
|
171
|
+
if is_critical:
|
|
172
|
+
free_gb = free / (1024**3)
|
|
173
|
+
issues.append(
|
|
174
|
+
DiagnosticIssue(
|
|
175
|
+
code="TZ-SYS-050",
|
|
176
|
+
category=DiagnosticCategory.SYSTEM_ENVIRONMENT,
|
|
177
|
+
severity=SeverityLevel.CRITICAL,
|
|
178
|
+
message=f"Critically low disk space on {mount}: {free_gb:.2f} GB free ({pct:.1f}% used).",
|
|
179
|
+
remediation="Free up space or purge cached build artifacts and package caches.",
|
|
180
|
+
|
|
181
|
+
)
|
|
182
|
+
)
|
|
183
|
+
elif is_warning:
|
|
184
|
+
free_gb = free / (1024**3)
|
|
185
|
+
issues.append(
|
|
186
|
+
DiagnosticIssue(
|
|
187
|
+
code="TZ-SYS-051",
|
|
188
|
+
category=DiagnosticCategory.SYSTEM_ENVIRONMENT,
|
|
189
|
+
severity=SeverityLevel.WARNING,
|
|
190
|
+
message=f"Low disk space warning on {mount}: {free_gb:.2f} GB free ({pct:.1f}% used).",
|
|
191
|
+
remediation="Consider cleaning temp files, docker containers, and stale python venvs.",
|
|
192
|
+
|
|
193
|
+
)
|
|
194
|
+
)
|
|
195
|
+
except Exception:
|
|
196
|
+
continue
|
|
197
|
+
|
|
198
|
+
return partitions, issues
|
|
199
|
+
|
|
200
|
+
def inspect_temp_directory_exhaustion(self) -> Tuple[bool, List[DiagnosticIssue]]:
|
|
201
|
+
"""
|
|
202
|
+
Checks if system temp directory is cluttered with >5,000 stale temp files
|
|
203
|
+
or large abandoned build directories.
|
|
204
|
+
"""
|
|
205
|
+
issues: List[DiagnosticIssue] = []
|
|
206
|
+
temp_dir = tempfile.gettempdir()
|
|
207
|
+
if not os.path.isdir(temp_dir):
|
|
208
|
+
return False, issues
|
|
209
|
+
|
|
210
|
+
try:
|
|
211
|
+
# Sample first 2000 entries to maintain ultra-fast performance
|
|
212
|
+
entries = os.listdir(temp_dir)[:2000]
|
|
213
|
+
stale_pip_builds = [e for e in entries if e.startswith("pip-") or e.startswith("tmp")]
|
|
214
|
+
if len(stale_pip_builds) > 200:
|
|
215
|
+
issues.append(
|
|
216
|
+
DiagnosticIssue(
|
|
217
|
+
code="TZ-SYS-052",
|
|
218
|
+
category=DiagnosticCategory.SYSTEM_ENVIRONMENT,
|
|
219
|
+
severity=SeverityLevel.INFO,
|
|
220
|
+
message=f"Detected {len(stale_pip_builds)}+ stale pip/build folders in temporary directory: {temp_dir}",
|
|
221
|
+
remediation="Run system temp directory cleaner to reclaim storage and file handles.",
|
|
222
|
+
|
|
223
|
+
)
|
|
224
|
+
)
|
|
225
|
+
return True, issues
|
|
226
|
+
except Exception:
|
|
227
|
+
pass
|
|
228
|
+
|
|
229
|
+
return False, issues
|
|
230
|
+
|
|
231
|
+
# -------------------------------------------------------------------------
|
|
232
|
+
# 2. Network Port Conflicts & Dev Servers
|
|
233
|
+
# -------------------------------------------------------------------------
|
|
234
|
+
def inspect_dev_ports(self) -> Tuple[List[NetworkPortStatus], List[DiagnosticIssue]]:
|
|
235
|
+
"""
|
|
236
|
+
Fast local socket scan across standard development server ports.
|
|
237
|
+
Identifies ports already bound which might cause 'EADDRINUSE' errors.
|
|
238
|
+
"""
|
|
239
|
+
active_ports: List[NetworkPortStatus] = []
|
|
240
|
+
issues: List[DiagnosticIssue] = []
|
|
241
|
+
|
|
242
|
+
for port, service_hint in self.COMMON_DEV_PORTS.items():
|
|
243
|
+
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
244
|
+
sock.settimeout(0.04) # 40ms fast non-blocking probe
|
|
245
|
+
try:
|
|
246
|
+
result = sock.connect_ex(("127.0.0.1", port))
|
|
247
|
+
if result == 0:
|
|
248
|
+
status = NetworkPortStatus(
|
|
249
|
+
port=port,
|
|
250
|
+
service_hint=service_hint,
|
|
251
|
+
is_open=True,
|
|
252
|
+
)
|
|
253
|
+
active_ports.append(status)
|
|
254
|
+
except Exception:
|
|
255
|
+
pass
|
|
256
|
+
finally:
|
|
257
|
+
sock.close()
|
|
258
|
+
|
|
259
|
+
if active_ports:
|
|
260
|
+
summary_list = [f":{p.port} ({p.service_hint})" for p in active_ports[:5]]
|
|
261
|
+
issues.append(
|
|
262
|
+
DiagnosticIssue(
|
|
263
|
+
code="TZ-NET-010",
|
|
264
|
+
category=DiagnosticCategory.SYSTEM_ENVIRONMENT,
|
|
265
|
+
severity=SeverityLevel.INFO,
|
|
266
|
+
message=f"Active development/database ports detected: {', '.join(summary_list)}",
|
|
267
|
+
remediation="Verify port conflicts if launching new servers on these ports.",
|
|
268
|
+
|
|
269
|
+
)
|
|
270
|
+
)
|
|
271
|
+
|
|
272
|
+
return active_ports, issues
|
|
273
|
+
|
|
274
|
+
# -------------------------------------------------------------------------
|
|
275
|
+
# 3. Windows Specific Deep Registry Diagnostics
|
|
276
|
+
# -------------------------------------------------------------------------
|
|
277
|
+
def inspect_windows_registry_policies(self) -> List[DiagnosticIssue]:
|
|
278
|
+
"""
|
|
279
|
+
Checks critical Windows developer settings via registry inspection:
|
|
280
|
+
1. LongPathsEnabled (avoids 260 character MAX_PATH failures in node_modules and python venvs)
|
|
281
|
+
2. DeveloperMode (allows symlink creation without UAC elevation)
|
|
282
|
+
"""
|
|
283
|
+
issues: List[DiagnosticIssue] = []
|
|
284
|
+
if self.platform != SystemPlatform.WINDOWS:
|
|
285
|
+
return issues
|
|
286
|
+
|
|
287
|
+
try:
|
|
288
|
+
import winreg
|
|
289
|
+
|
|
290
|
+
# 1. Check LongPathsEnabled
|
|
291
|
+
try:
|
|
292
|
+
with winreg.OpenKey(
|
|
293
|
+
winreg.HKEY_LOCAL_MACHINE,
|
|
294
|
+
r"SYSTEM\CurrentControlSet\Control\FileSystem",
|
|
295
|
+
0,
|
|
296
|
+
winreg.KEY_READ,
|
|
297
|
+
) as key:
|
|
298
|
+
val, _ = winreg.QueryValueEx(key, "LongPathsEnabled")
|
|
299
|
+
if val != 1:
|
|
300
|
+
issues.append(
|
|
301
|
+
DiagnosticIssue(
|
|
302
|
+
code="TZ-WIN-001",
|
|
303
|
+
category=DiagnosticCategory.SYSTEM_ENVIRONMENT,
|
|
304
|
+
severity=SeverityLevel.WARNING,
|
|
305
|
+
message="Windows LongPathsEnabled is disabled. Deep paths in node_modules or venvs may crash tools.",
|
|
306
|
+
remediation="Enable LongPaths via registry: HKLM\\SYSTEM\\CurrentControlSet\\Control\\FileSystem\\LongPathsEnabled=1",
|
|
307
|
+
|
|
308
|
+
)
|
|
309
|
+
)
|
|
310
|
+
except (FileNotFoundError, OSError):
|
|
311
|
+
issues.append(
|
|
312
|
+
DiagnosticIssue(
|
|
313
|
+
code="TZ-WIN-001",
|
|
314
|
+
category=DiagnosticCategory.SYSTEM_ENVIRONMENT,
|
|
315
|
+
severity=SeverityLevel.WARNING,
|
|
316
|
+
message="Windows LongPathsEnabled registry key not found (defaulting to 260 char limit).",
|
|
317
|
+
remediation="Set LongPathsEnabled=1 to prevent MAX_PATH path overflow errors.",
|
|
318
|
+
|
|
319
|
+
)
|
|
320
|
+
)
|
|
321
|
+
|
|
322
|
+
# 2. Check Developer Mode / Symlink Permission
|
|
323
|
+
try:
|
|
324
|
+
with winreg.OpenKey(
|
|
325
|
+
winreg.HKEY_LOCAL_MACHINE,
|
|
326
|
+
r"SOFTWARE\Microsoft\Windows\CurrentVersion\AppModelUnlock",
|
|
327
|
+
0,
|
|
328
|
+
winreg.KEY_READ,
|
|
329
|
+
) as key:
|
|
330
|
+
val, _ = winreg.QueryValueEx(key, "AllowDevelopmentWithoutDevLicense")
|
|
331
|
+
if val != 1:
|
|
332
|
+
issues.append(
|
|
333
|
+
DiagnosticIssue(
|
|
334
|
+
code="TZ-WIN-002",
|
|
335
|
+
category=DiagnosticCategory.SYSTEM_ENVIRONMENT,
|
|
336
|
+
severity=SeverityLevel.INFO,
|
|
337
|
+
message="Windows Developer Mode is not active. Creating symlinks requires Administrator privileges.",
|
|
338
|
+
remediation="Enable Developer Mode in Windows Settings or enable symlinks for non-admin users.",
|
|
339
|
+
|
|
340
|
+
)
|
|
341
|
+
)
|
|
342
|
+
except (FileNotFoundError, OSError):
|
|
343
|
+
pass
|
|
344
|
+
|
|
345
|
+
except ImportError:
|
|
346
|
+
pass
|
|
347
|
+
|
|
348
|
+
return issues
|
|
349
|
+
|
|
350
|
+
# -------------------------------------------------------------------------
|
|
351
|
+
# 4. POSIX Permissions & Security Diagnostics (Linux/macOS)
|
|
352
|
+
# -------------------------------------------------------------------------
|
|
353
|
+
def inspect_posix_permissions(self) -> List[DiagnosticIssue]:
|
|
354
|
+
"""
|
|
355
|
+
Verifies correct permissions on user SSH keys, git credentials, and tmp directory.
|
|
356
|
+
"""
|
|
357
|
+
issues: List[DiagnosticIssue] = []
|
|
358
|
+
if self.platform not in (SystemPlatform.LINUX, SystemPlatform.MACOS):
|
|
359
|
+
return issues
|
|
360
|
+
|
|
361
|
+
home_dir = os.path.expanduser("~")
|
|
362
|
+
ssh_dir = os.path.join(home_dir, ".ssh")
|
|
363
|
+
|
|
364
|
+
if os.path.isdir(ssh_dir):
|
|
365
|
+
try:
|
|
366
|
+
ssh_stat = os.stat(ssh_dir)
|
|
367
|
+
mode = ssh_stat.st_mode & 0o777
|
|
368
|
+
if mode != 0o700:
|
|
369
|
+
issues.append(
|
|
370
|
+
DiagnosticIssue(
|
|
371
|
+
code="TZ-SEC-080",
|
|
372
|
+
category=DiagnosticCategory.SECURITY_CREDENTIAL,
|
|
373
|
+
severity=SeverityLevel.WARNING,
|
|
374
|
+
file_path=ssh_dir,
|
|
375
|
+
message=f"Insecure permissions on ~/.ssh: {oct(mode)} (expected 0700). SSH connections may be rejected.",
|
|
376
|
+
remediation="Run: chmod 700 ~/.ssh",
|
|
377
|
+
|
|
378
|
+
)
|
|
379
|
+
)
|
|
380
|
+
|
|
381
|
+
# Check private key files
|
|
382
|
+
for key_name in ["id_rsa", "id_ed25519", "id_ecdsa"]:
|
|
383
|
+
key_file = os.path.join(ssh_dir, key_name)
|
|
384
|
+
if os.path.isfile(key_file):
|
|
385
|
+
kmode = os.stat(key_file).st_mode & 0o777
|
|
386
|
+
if kmode not in (0o600, 0o400):
|
|
387
|
+
issues.append(
|
|
388
|
+
DiagnosticIssue(
|
|
389
|
+
code="TZ-SEC-081",
|
|
390
|
+
category=DiagnosticCategory.SECURITY_CREDENTIAL,
|
|
391
|
+
severity=SeverityLevel.CRITICAL,
|
|
392
|
+
file_path=key_file,
|
|
393
|
+
message=f"Insecure permissions on private key {key_name}: {oct(kmode)} (expected 0600).",
|
|
394
|
+
remediation=f"Run: chmod 600 {key_file}",
|
|
395
|
+
|
|
396
|
+
)
|
|
397
|
+
)
|
|
398
|
+
except Exception:
|
|
399
|
+
pass
|
|
400
|
+
|
|
401
|
+
return issues
|
|
402
|
+
|
|
403
|
+
# -------------------------------------------------------------------------
|
|
404
|
+
# 5. Stale Build Artifacts & Lockfile Accumulation
|
|
405
|
+
# -------------------------------------------------------------------------
|
|
406
|
+
def inspect_stale_build_artifacts(self) -> Tuple[List[str], List[DiagnosticIssue]]:
|
|
407
|
+
"""
|
|
408
|
+
Detects massive accumulations of build artifacts, test caches, and orphaned locks
|
|
409
|
+
in the workspace (`.pytest_cache`, `.mypy_cache`, `.ruff_cache`, `target/`, `dist/`).
|
|
410
|
+
"""
|
|
411
|
+
detected: List[str] = []
|
|
412
|
+
issues: List[DiagnosticIssue] = []
|
|
413
|
+
|
|
414
|
+
cache_dirs = [
|
|
415
|
+
".pytest_cache",
|
|
416
|
+
".mypy_cache",
|
|
417
|
+
".ruff_cache",
|
|
418
|
+
".tox",
|
|
419
|
+
".nox",
|
|
420
|
+
".coverage",
|
|
421
|
+
".parcel-cache",
|
|
422
|
+
".turbo",
|
|
423
|
+
".next/cache",
|
|
424
|
+
]
|
|
425
|
+
|
|
426
|
+
total_cache_size = 0
|
|
427
|
+
for cd in cache_dirs:
|
|
428
|
+
target = self.workspace_path / cd
|
|
429
|
+
if target.exists():
|
|
430
|
+
try:
|
|
431
|
+
if target.is_dir():
|
|
432
|
+
size = sum(f.stat().st_size for f in target.glob("**/*") if f.is_file())
|
|
433
|
+
else:
|
|
434
|
+
size = target.stat().st_size
|
|
435
|
+
total_cache_size += size
|
|
436
|
+
detected.append(f"{cd} ({size / (1024*1024):.1f} MB)")
|
|
437
|
+
except Exception:
|
|
438
|
+
detected.append(cd)
|
|
439
|
+
|
|
440
|
+
if total_cache_size > 500 * 1024 * 1024: # > 500 MB
|
|
441
|
+
mb = total_cache_size / (1024 * 1024)
|
|
442
|
+
issues.append(
|
|
443
|
+
DiagnosticIssue(
|
|
444
|
+
code="TZ-SYS-055",
|
|
445
|
+
category=DiagnosticCategory.SYSTEM_ENVIRONMENT,
|
|
446
|
+
severity=SeverityLevel.INFO,
|
|
447
|
+
message=f"Workspace cache directories consuming {mb:.1f} MB across: {', '.join(detected[:4])}",
|
|
448
|
+
remediation="Clean build and test caches with 'tzero clean' or remove unneeded cache folders.",
|
|
449
|
+
|
|
450
|
+
)
|
|
451
|
+
)
|
|
452
|
+
|
|
453
|
+
return detected, issues
|
|
454
|
+
|
|
455
|
+
# -------------------------------------------------------------------------
|
|
456
|
+
# 6. Comprehensive Scan Aggregate
|
|
457
|
+
# -------------------------------------------------------------------------
|
|
458
|
+
def run_all_extended_diagnostics(self) -> Tuple[ExtendedDiagnosticSummary, List[DiagnosticIssue]]:
|
|
459
|
+
"""
|
|
460
|
+
Executes all extended diagnostics in parallel-safe, zero-side-effect mode.
|
|
461
|
+
Returns aggregate summary and normalized DiagnosticIssues.
|
|
462
|
+
"""
|
|
463
|
+
all_issues: List[DiagnosticIssue] = []
|
|
464
|
+
|
|
465
|
+
partitions, disk_issues = self.inspect_disk_health()
|
|
466
|
+
all_issues.extend(disk_issues)
|
|
467
|
+
|
|
468
|
+
temp_exhausted, temp_issues = self.inspect_temp_directory_exhaustion()
|
|
469
|
+
all_issues.extend(temp_issues)
|
|
470
|
+
|
|
471
|
+
open_ports, port_issues = self.inspect_dev_ports()
|
|
472
|
+
all_issues.extend(port_issues)
|
|
473
|
+
|
|
474
|
+
reg_issues = self.inspect_windows_registry_policies()
|
|
475
|
+
all_issues.extend(reg_issues)
|
|
476
|
+
|
|
477
|
+
posix_issues = self.inspect_posix_permissions()
|
|
478
|
+
all_issues.extend(posix_issues)
|
|
479
|
+
|
|
480
|
+
caches, cache_issues = self.inspect_stale_build_artifacts()
|
|
481
|
+
all_issues.extend(cache_issues)
|
|
482
|
+
|
|
483
|
+
summary = ExtendedDiagnosticSummary(
|
|
484
|
+
platform=self.platform,
|
|
485
|
+
disk_health=partitions,
|
|
486
|
+
port_conflicts=open_ports,
|
|
487
|
+
temp_dir_exhaustion=temp_exhausted,
|
|
488
|
+
stale_locks_detected=caches,
|
|
489
|
+
permission_issues=[i.message for i in posix_issues],
|
|
490
|
+
registry_recommendations=[i.message for i in reg_issues],
|
|
491
|
+
)
|
|
492
|
+
|
|
493
|
+
return summary, all_issues
|