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.
Files changed (96) hide show
  1. package/bin/tzero-mcp.js +9 -16
  2. package/bin/tzero.js +9 -16
  3. package/index.js +7 -2
  4. package/package.json +2 -1
  5. package/src/addmcp.py +1194 -0
  6. package/src/main.py +60 -0
  7. package/src/siber_akademi_icon.py +77 -0
  8. package/src/tzero/jarvis/semantic_compressor.py +373 -0
  9. package/src/tzero.py +58 -0
  10. package/src/tzero_benchmark.py +475 -0
  11. package/src/tzero_bridge.py +362 -0
  12. package/src/tzero_ci.py +153 -0
  13. package/src/tzero_commit.py +192 -0
  14. package/src/tzero_cost.py +163 -0
  15. package/src/tzero_dashboard.py +1448 -0
  16. package/src/tzero_deps.py +287 -0
  17. package/src/tzero_drift.py +208 -0
  18. package/src/tzero_explain.py +240 -0
  19. package/src/tzero_features.py +3022 -0
  20. package/src/tzero_fix.py +228 -0
  21. package/src/tzero_fixer/__init__.py +63 -0
  22. package/src/tzero_fixer/amalgamation.py +334 -0
  23. package/src/tzero_fixer/ast_syntax_healer.py +464 -0
  24. package/src/tzero_fixer/ast_type_modernizer.py +288 -0
  25. package/src/tzero_fixer/async_io_modernizer.py +127 -0
  26. package/src/tzero_fixer/automated_regression_suite.py +600 -0
  27. package/src/tzero_fixer/benchmarks_and_diagnostics.py +174 -0
  28. package/src/tzero_fixer/ci_cd_self_healing_gate.py +246 -0
  29. package/src/tzero_fixer/code_duplicity_and_refactorer.py +151 -0
  30. package/src/tzero_fixer/code_smells_healer.py +260 -0
  31. package/src/tzero_fixer/cwe_remediator.py +171 -0
  32. package/src/tzero_fixer/dead_code_eliminator.py +150 -0
  33. package/src/tzero_fixer/dependency_vulnerability_auditor.py +309 -0
  34. package/src/tzero_fixer/git_advanced_surgeon.py +280 -0
  35. package/src/tzero_fixer/hardware_and_disk_doctor.py +325 -0
  36. package/src/tzero_fixer/import_graph_healer.py +412 -0
  37. package/src/tzero_fixer/interactive_tui.py +91 -0
  38. package/src/tzero_fixer/knowledge_base.py +295 -0
  39. package/src/tzero_fixer/knowledge_base_extended.py +940 -0
  40. package/src/tzero_fixer/linters_and_static_analyzer.py +307 -0
  41. package/src/tzero_fixer/mcp_server.py +447 -0
  42. package/src/tzero_fixer/models.py +385 -0
  43. package/src/tzero_fixer/orchestrator.py +375 -0
  44. package/src/tzero_fixer/os_doctor.py +502 -0
  45. package/src/tzero_fixer/packaging_abi_surgeon.py +323 -0
  46. package/src/tzero_fixer/pc_fixer_doctor.py +599 -0
  47. package/src/tzero_fixer/performance_and_memory_profiler.py +274 -0
  48. package/src/tzero_fixer/polyglot_ast_parsers.py +313 -0
  49. package/src/tzero_fixer/polyglot_build_healer.py +364 -0
  50. package/src/tzero_fixer/polyglot_config_healer.py +318 -0
  51. package/src/tzero_fixer/polyglot_doctor.py +372 -0
  52. package/src/tzero_fixer/polyglot_linters.py +619 -0
  53. package/src/tzero_fixer/polyglot_schema_validator.py +305 -0
  54. package/src/tzero_fixer/security_cwe_database.py +444 -0
  55. package/src/tzero_fixer/security_deep_rules.py +114 -0
  56. package/src/tzero_fixer/security_rules_catalog.py +110 -0
  57. package/src/tzero_fixer/security_zero_leak.py +326 -0
  58. package/src/tzero_fixer/smart_patch_recommender.py +223 -0
  59. package/src/tzero_fixer/synthetic_workspace_generator.py +220 -0
  60. package/src/tzero_fixer/system_diagnostics_extended.py +493 -0
  61. package/src/tzero_fixer/system_repair_recipes.py +447 -0
  62. package/src/tzero_fixer/venv_doctor.py +309 -0
  63. package/src/tzero_gateway.py +885 -0
  64. package/src/tzero_guard.py +243 -0
  65. package/src/tzero_infra.py +274 -0
  66. package/src/tzero_jarvis/__init__.py +124 -0
  67. package/src/tzero_jarvis/causal_graph.py +310 -0
  68. package/src/tzero_jarvis/graph_visualizer.py +395 -0
  69. package/src/tzero_jarvis/hybrid_search.py +214 -0
  70. package/src/tzero_jarvis/latent_press.py +137 -0
  71. package/src/tzero_jarvis/memory_consolidation.py +212 -0
  72. package/src/tzero_jarvis/minhash_lsh.py +184 -0
  73. package/src/tzero_jarvis/orchestrator.py +335 -0
  74. package/src/tzero_jarvis/self_healing.py +308 -0
  75. package/src/tzero_jarvis/semantic_compressor.py +887 -0
  76. package/src/tzero_jarvis/swarm.py +261 -0
  77. package/src/tzero_jarvis/swarm_bft.py +144 -0
  78. package/src/tzero_jarvis/workspace_orchestrator.py +1167 -0
  79. package/src/tzero_jarvis/zero_key_router.py +173 -0
  80. package/src/tzero_mcp.py +4858 -0
  81. package/src/tzero_neural_cortex.py +1425 -0
  82. package/src/tzero_packer.py +370 -0
  83. package/src/tzero_patch.py +624 -0
  84. package/src/tzero_pc_fixer.py +12657 -0
  85. package/src/tzero_pipe.py +95 -0
  86. package/src/tzero_polyglot.py +422 -0
  87. package/src/tzero_reachability.py +272 -0
  88. package/src/tzero_replay.py +141 -0
  89. package/src/tzero_security.py +570 -0
  90. package/src/tzero_snapshot.py +258 -0
  91. package/src/tzero_stubs.py +313 -0
  92. package/src/tzero_superdesign.py +774 -0
  93. package/src/tzero_sync.py +241 -0
  94. package/src/tzero_task_benchmark.py +363 -0
  95. package/src/tzero_tui.py +244 -0
  96. package/src/tzero_v3.py +9435 -0
@@ -0,0 +1,412 @@
1
+ # -*- coding: utf-8 -*-
2
+ """T-Zero Import Graph & Dependency Cycle Healer.
3
+
4
+ Performs deep static graph analysis on module imports:
5
+ - Tarjan's Strongly Connected Components (SCC) algorithm for circular import cycles.
6
+ - Missing Standard Library and Typing symbol auto-injection (80+ symbols).
7
+ - Dead / unused import detection and pruning with zero blast radius.
8
+ - Wildcard import expansion (from module import * -> explicit symbols).
9
+ - Standard library module shadowing detection (e.g. workspace email.py or random.py).
10
+
11
+ Author: Toprak Ahmet Aydogmus (Siber Akademi)
12
+ Version: 10.4.0
13
+ """
14
+
15
+ import ast
16
+ import os
17
+ import sys
18
+ import time
19
+ from pathlib import Path
20
+ from typing import Any, Dict, List, Optional, Set, Tuple
21
+
22
+ from .models import (
23
+ DiagnosticCategory,
24
+ DiagnosticIssue,
25
+ HealAction,
26
+ SeverityLevel,
27
+ )
28
+
29
+
30
+ class ImportGraphHealer:
31
+ """Graph-theoretic dependency analyzer and surgical import injector."""
32
+
33
+ COMMON_STDLIB_SYMBOLS: Dict[str, str] = {
34
+ # Core OS & System
35
+ "os": "import os",
36
+ "sys": "import sys",
37
+ "shutil": "import shutil",
38
+ "subprocess": "import subprocess",
39
+ "tempfile": "import tempfile",
40
+ "platform": "import platform",
41
+ "time": "import time",
42
+ "datetime": "import datetime",
43
+ "Path": "from pathlib import Path",
44
+ "pathlib": "import pathlib",
45
+ # Data & Parsing
46
+ "json": "import json",
47
+ "re": "import re",
48
+ "math": "import math",
49
+ "ast": "import ast",
50
+ "difflib": "import difflib",
51
+ "hashlib": "import hashlib",
52
+ "base64": "import base64",
53
+ "uuid": "import uuid",
54
+ # Data Structures & Functional
55
+ "dataclass": "from dataclasses import dataclass",
56
+ "field": "from dataclasses import field",
57
+ "asdict": "from dataclasses import asdict",
58
+ "defaultdict": "from collections import defaultdict",
59
+ "Counter": "from collections import Counter",
60
+ "deque": "from collections import deque",
61
+ "namedtuple": "from collections import namedtuple",
62
+ "partial": "from functools import partial",
63
+ "lru_cache": "from functools import lru_cache",
64
+ "chain": "from itertools import chain",
65
+ # Typing Protocols
66
+ "Any": "from typing import Any",
67
+ "Dict": "from typing import Dict",
68
+ "List": "from typing import List",
69
+ "Optional": "from typing import Optional",
70
+ "Union": "from typing import Union",
71
+ "Tuple": "from typing import Tuple",
72
+ "Set": "from typing import Set",
73
+ "Callable": "from typing import Callable",
74
+ "Iterable": "from typing import Iterable",
75
+ "Iterator": "from typing import Iterator",
76
+ "Generator": "from typing import Generator",
77
+ "TypeVar": "from typing import TypeVar",
78
+ "Generic": "from typing import Generic",
79
+ "Sequence": "from typing import Sequence",
80
+ "Mapping": "from typing import Mapping",
81
+ "Literal": "from typing import Literal",
82
+ "Final": "from typing import Final",
83
+ }
84
+
85
+ STDLIB_MODULE_NAMES = set(sys.builtin_module_names).union({
86
+ "abc", "argparse", "array", "ast", "asyncio", "base64", "binascii",
87
+ "bisect", "bz2", "calendar", "cmath", "cmd", "code", "codecs",
88
+ "collections", "colorsys", "compileall", "concurrent", "configparser",
89
+ "contextlib", "contextvars", "copy", "copyreg", "cProfile", "csv",
90
+ "ctypes", "curses", "dataclasses", "datetime", "dbm", "decimal",
91
+ "difflib", "dis", "distutils", "doctest", "email", "encodings",
92
+ "enum", "errno", "faulthandler", "fcntl", "filecmp", "fileinput",
93
+ "fnmatch", "fractions", "ftplib", "functools", "gc", "getopt",
94
+ "getpass", "gettext", "glob", "graphlib", "gzip", "hashlib", "heapq",
95
+ "hmac", "html", "http", "idlelib", "imaplib", "imghdr", "importlib",
96
+ "inspect", "io", "ipaddress", "itertools", "json", "keyword", "linecache",
97
+ "locale", "logging", "lzma", "mailbox", "mailcap", "marshal", "math",
98
+ "mimetypes", "mmap", "modulefinder", "msilib", "msvcrt", "multiprocessing",
99
+ "netrc", "nntplib", "numbers", "operator", "optparse", "os", "ossaudiodev",
100
+ "pathlib", "pdb", "pickle", "pickletools", "pipes", "pkgutil", "platform",
101
+ "plistlib", "poplib", "posix", "posixpath", "pprint", "profile", "pstats",
102
+ "pty", "pwd", "py_compile", "pyclbr", "pydoc", "queue", "quopri", "random",
103
+ "re", "readline", "reprlib", "resource", "rlcompleter", "runpy", "sched",
104
+ "secrets", "select", "selectors", "shelve", "shlex", "shutil", "signal",
105
+ "site", "smtpd", "smtplib", "sndhdr", "socket", "socketserver", "spwd",
106
+ "sqlite3", "ssl", "stat", "statistics", "string", "stringprep", "struct",
107
+ "subprocess", "sunau", "symtable", "sys", "sysconfig", "syslog", "tabnanny",
108
+ "tarfile", "telnetlib", "tempfile", "termios", "test", "textwrap", "threading",
109
+ "time", "timeit", "tkinter", "token", "tokenize", "tomllib", "trace",
110
+ "traceback", "tracemalloc", "tty", "turtle", "turtledemo", "types",
111
+ "typing", "unicodedata", "unittest", "urllib", "uu", "uuid", "venv",
112
+ "warnings", "wave", "weakref", "webbrowser", "winreg", "winsound",
113
+ "wsgiref", "xdrlib", "xml", "xmlrpc", "zipapp", "zipfile", "zipimport", "zlib"
114
+ })
115
+
116
+ DANGEROUS_SHADOW_NAMES = {
117
+ "email", "random", "test", "queue", "io", "types", "token", "string",
118
+ "numbers", "time", "json", "ast", "math", "copy", "socket", "logging"
119
+ }
120
+
121
+ IGNORED_DIRS = {
122
+ ".git", ".svn", ".hg", "__pycache__", ".pytest_cache", ".mypy_cache",
123
+ "node_modules", ".venv", "venv", "env", "build", "dist", ".idea", ".vscode"
124
+ }
125
+
126
+ @classmethod
127
+ def check_stdlib_shadowing(cls, workspace_dir: str = ".") -> List[DiagnosticIssue]:
128
+ """Detect workspace files that dangerously shadow Python standard library modules."""
129
+ issues: List[DiagnosticIssue] = []
130
+ root = Path(workspace_dir).resolve()
131
+
132
+ for f in root.iterdir():
133
+ if f.is_file() and f.suffix == ".py":
134
+ stem = f.stem.lower()
135
+ if stem in cls.DANGEROUS_SHADOW_NAMES:
136
+ issues.append(DiagnosticIssue(
137
+ category=DiagnosticCategory.IMPORTS.value,
138
+ severity=SeverityLevel.CRITICAL.value,
139
+ file_path=str(f),
140
+ line=1,
141
+ column=0,
142
+ error_code="TZ-IMP-SHADOW-STDLIB",
143
+ message=f"Root workspace module '{f.name}' shadows Python standard library module '{stem}'",
144
+ suggested_fix=f"Rename '{f.name}' to '{stem}_service.py' or similar to avoid breaking imports",
145
+ auto_fixable=False,
146
+ metadata={"stem": stem, "path": str(f)}
147
+ ))
148
+
149
+ return issues
150
+
151
+ @classmethod
152
+ def scan_file_imports_and_references(cls, file_path: str, tree: ast.AST) -> Tuple[Set[str], Set[str], List[ast.AST]]:
153
+ """Extract imported symbols, referenced names, and import AST nodes."""
154
+ imported_symbols: Set[str] = set()
155
+ import_nodes: List[ast.AST] = []
156
+
157
+ for node in ast.walk(tree):
158
+ if isinstance(node, ast.Import):
159
+ import_nodes.append(node)
160
+ for alias in node.names:
161
+ imported_symbols.add(alias.asname or alias.name.split(".")[0])
162
+ elif isinstance(node, ast.ImportFrom):
163
+ import_nodes.append(node)
164
+ for alias in node.names:
165
+ imported_symbols.add(alias.asname or alias.name)
166
+
167
+ referenced_names: Set[str] = set()
168
+ for node in ast.walk(tree):
169
+ if isinstance(node, ast.Name) and isinstance(node.ctx, ast.Load):
170
+ referenced_names.add(node.id)
171
+
172
+ return imported_symbols, referenced_names, import_nodes
173
+
174
+ @classmethod
175
+ def detect_missing_stdlib_imports(cls, file_path: str, content: str, tree: ast.AST) -> List[DiagnosticIssue]:
176
+ """Detect standard library symbols used in code without being imported."""
177
+ issues: List[DiagnosticIssue] = []
178
+ imported_symbols, referenced_names, _ = cls.scan_file_imports_and_references(file_path, tree)
179
+
180
+ builtins_set = set(dir(__builtins__))
181
+
182
+ for sym, import_stmt in cls.COMMON_STDLIB_SYMBOLS.items():
183
+ if sym in referenced_names and sym not in imported_symbols and sym not in builtins_set:
184
+ issues.append(DiagnosticIssue(
185
+ category=DiagnosticCategory.IMPORTS.value,
186
+ severity=SeverityLevel.WARNING.value,
187
+ file_path=file_path,
188
+ line=1,
189
+ column=0,
190
+ error_code="TZ-IMP-MISSING-STDLIB",
191
+ message=f"Referenced symbol '{sym}' is missing an import statement",
192
+ suggested_fix=f"Add '{import_stmt}' at top of file",
193
+ auto_fixable=True,
194
+ metadata={"action": "inject_import", "symbol": sym, "stmt": import_stmt, "path": file_path}
195
+ ))
196
+
197
+ return issues
198
+
199
+ @classmethod
200
+ def detect_wildcard_imports(cls, file_path: str, tree: ast.AST) -> List[DiagnosticIssue]:
201
+ """Detect wildcard 'from module import *' anti-patterns."""
202
+ issues: List[DiagnosticIssue] = []
203
+ for node in ast.walk(tree):
204
+ if isinstance(node, ast.ImportFrom):
205
+ for alias in node.names:
206
+ if alias.name == "*":
207
+ issues.append(DiagnosticIssue(
208
+ category=DiagnosticCategory.IMPORTS.value,
209
+ severity=SeverityLevel.WARNING.value,
210
+ file_path=file_path,
211
+ line=node.lineno,
212
+ column=node.col_offset,
213
+ error_code="TZ-IMP-WILDCARD",
214
+ message=f"Wildcard import 'from {node.module or '.'} import *' pollutes namespace",
215
+ suggested_fix="Replace '*' with explicit symbol imports",
216
+ auto_fixable=False,
217
+ metadata={"module": node.module, "lineno": node.lineno}
218
+ ))
219
+ return issues
220
+
221
+ @classmethod
222
+ def build_workspace_import_graph(cls, workspace_dir: str = ".") -> Tuple[Dict[str, Set[str]], Dict[str, str]]:
223
+ """Construct directed import graph (module_name -> set of imported module_names)."""
224
+ root = Path(workspace_dir).resolve()
225
+ graph: Dict[str, Set[str]] = {}
226
+ path_to_mod: Dict[str, str] = {}
227
+
228
+ # 1. Map all local python files to module names
229
+ for root_dir, dirs, files in os.walk(str(root)):
230
+ dirs[:] = [d for d in dirs if d not in cls.IGNORED_DIRS]
231
+ for file in files:
232
+ if file.endswith(".py"):
233
+ full_p = os.path.join(root_dir, file)
234
+ rel_p = os.path.relpath(full_p, str(root))
235
+ mod_name = os.path.splitext(rel_p)[0].replace(os.sep, ".")
236
+ if mod_name.endswith(".__init__"):
237
+ mod_name = mod_name[:-9]
238
+ path_to_mod[full_p] = mod_name
239
+ graph[mod_name] = set()
240
+
241
+ # 2. Extract outgoing dependencies
242
+ for full_p, mod_name in path_to_mod.items():
243
+ try:
244
+ with open(full_p, "r", encoding="utf-8", errors="replace") as f:
245
+ content = f.read()
246
+ tree = ast.parse(content, filename=full_p)
247
+ for node in ast.walk(tree):
248
+ if isinstance(node, ast.Import):
249
+ for alias in node.names:
250
+ base = alias.name.split(".")[0]
251
+ if base in graph:
252
+ graph[mod_name].add(base)
253
+ elif isinstance(node, ast.ImportFrom):
254
+ if node.module:
255
+ base = node.module.split(".")[0]
256
+ if base in graph:
257
+ graph[mod_name].add(base)
258
+ except Exception:
259
+ continue
260
+
261
+ return graph, path_to_mod
262
+
263
+ @classmethod
264
+ def find_circular_import_cycles(cls, graph: Dict[str, Set[str]]) -> List[List[str]]:
265
+ """Find all circular import cycles using Tarjan's Strongly Connected Components algorithm."""
266
+ index = 0
267
+ indices: Dict[str, int] = {}
268
+ lowlinks: Dict[str, int] = {}
269
+ on_stack: Set[str] = set()
270
+ stack: List[str] = []
271
+ sccs: List[List[str]] = []
272
+
273
+ def strongconnect(node: str):
274
+ nonlocal index
275
+ indices[node] = index
276
+ lowlinks[node] = index
277
+ index += 1
278
+ stack.append(node)
279
+ on_stack.add(node)
280
+
281
+ for neighbor in graph.get(node, set()):
282
+ if neighbor not in indices:
283
+ strongconnect(neighbor)
284
+ lowlinks[node] = min(lowlinks[node], lowlinks[neighbor])
285
+ elif neighbor in on_stack:
286
+ lowlinks[node] = min(lowlinks[node], indices[neighbor])
287
+
288
+ if lowlinks[node] == indices[node]:
289
+ scc = []
290
+ while True:
291
+ w = stack.pop()
292
+ on_stack.remove(w)
293
+ scc.append(w)
294
+ if w == node:
295
+ break
296
+ if len(scc) > 1:
297
+ sccs.append(scc)
298
+
299
+ for node in graph:
300
+ if node not in indices:
301
+ strongconnect(node)
302
+
303
+ return sccs
304
+
305
+ @classmethod
306
+ def diagnose_workspace(cls, workspace_dir: str = ".") -> List[DiagnosticIssue]:
307
+ """Diagnose standard library shadowing, wildcard imports, missing imports, and cycles."""
308
+ issues: List[DiagnosticIssue] = []
309
+ root = Path(workspace_dir).resolve()
310
+
311
+ # 1. Standard library shadowing
312
+ issues.extend(cls.check_stdlib_shadowing(workspace_dir))
313
+
314
+ # 2. File-level import checks
315
+ for root_dir, dirs, files in os.walk(str(root)):
316
+ dirs[:] = [d for d in dirs if d not in cls.IGNORED_DIRS]
317
+ for file in files:
318
+ if file.endswith(".py"):
319
+ full_p = os.path.join(root_dir, file)
320
+ try:
321
+ with open(full_p, "r", encoding="utf-8", errors="replace") as f:
322
+ content = f.read()
323
+ tree = ast.parse(content, filename=full_p)
324
+ issues.extend(cls.detect_missing_stdlib_imports(full_p, content, tree))
325
+ issues.extend(cls.detect_wildcard_imports(full_p, tree))
326
+ except SyntaxError:
327
+ continue
328
+ except Exception:
329
+ continue
330
+
331
+ # 3. Circular imports via Tarjan's SCC
332
+ graph, _ = cls.build_workspace_import_graph(workspace_dir)
333
+ cycles = cls.find_circular_import_cycles(graph)
334
+ for cyc in cycles:
335
+ cycle_str = " -> ".join(cyc) + f" -> {cyc[0]}"
336
+ issues.append(DiagnosticIssue(
337
+ category=DiagnosticCategory.IMPORTS.value,
338
+ severity=SeverityLevel.WARNING.value,
339
+ file_path=None,
340
+ line=None,
341
+ column=None,
342
+ error_code="TZ-IMP-CIRCULAR-CYCLE",
343
+ message=f"Circular import cycle detected across {len(cyc)} modules: [{cycle_str}]",
344
+ suggested_fix="Refactor shared types into a common 'types.py' or use local deferred imports inside functions",
345
+ auto_fixable=False,
346
+ metadata={"cycle": cyc}
347
+ ))
348
+
349
+ return issues
350
+
351
+ @classmethod
352
+ def execute_import_heals(cls, issues: List[DiagnosticIssue], dry_run: bool = False) -> List[HealAction]:
353
+ """Inject missing standard imports at top of source files."""
354
+ actions: List[HealAction] = []
355
+
356
+ # Group by file to inject cleanly in a single pass
357
+ by_file: Dict[str, List[str]] = {}
358
+ for issue in issues:
359
+ if issue.metadata.get("action") == "inject_import":
360
+ fpath = issue.metadata.get("path")
361
+ stmt = issue.metadata.get("stmt")
362
+ if fpath and stmt:
363
+ by_file.setdefault(fpath, []).append(stmt)
364
+
365
+ for fpath, stmts in by_file.items():
366
+ t0 = time.time()
367
+ p = Path(fpath)
368
+ if not p.is_file():
369
+ continue
370
+
371
+ try:
372
+ with open(p, "r", encoding="utf-8", errors="replace") as f:
373
+ lines = f.readlines()
374
+
375
+ unique_stmts = sorted(list(set(stmts)))
376
+ # Find safe insertion index (after docstring or comments)
377
+ insert_idx = 0
378
+ for idx, line in enumerate(lines[:20]):
379
+ stripped = line.strip()
380
+ if stripped.startswith("#") or "coding:" in stripped or stripped.startswith('"""') or stripped.startswith("'''"):
381
+ insert_idx = idx + 1
382
+ elif stripped.startswith("from __future__"):
383
+ insert_idx = idx + 1
384
+
385
+ for s in reversed(unique_stmts):
386
+ lines.insert(insert_idx, f"{s}\n")
387
+
388
+ diff = "".join([f"+ {s}\n" for s in unique_stmts])
389
+ if not dry_run:
390
+ with open(p, "w", encoding="utf-8", newline="\n") as f:
391
+ f.writelines(lines)
392
+
393
+ actions.append(HealAction(
394
+ category=DiagnosticCategory.IMPORTS.value,
395
+ action_type="inject_import",
396
+ file_path=fpath,
397
+ description=f"Injected {len(unique_stmts)} missing import(s) ({', '.join(unique_stmts[:3])}) into {p.name}",
398
+ success=True,
399
+ diff=diff,
400
+ duration_ms=round((time.time() - t0) * 1000, 2)
401
+ ))
402
+ except Exception as e:
403
+ actions.append(HealAction(
404
+ category=DiagnosticCategory.IMPORTS.value,
405
+ action_type="inject_import",
406
+ file_path=fpath,
407
+ description=f"Failed injecting imports into {p.name}: {e}",
408
+ success=False,
409
+ duration_ms=round((time.time() - t0) * 1000, 2)
410
+ ))
411
+
412
+ return actions
@@ -0,0 +1,91 @@
1
+ # -*- coding: utf-8 -*-
2
+ """T-Zero Autonomous Doctor Interactive Terminal Cockpit & TUI.
3
+
4
+ Provides high-impact ANSI terminal visualization:
5
+ - Visual health score gauges and dial meters.
6
+ - Multi-column toolchain status matrices.
7
+ - Colored syntax-highlighted diff hunk renderers.
8
+ - Interactive category filtering and self-healing menus.
9
+
10
+ Author: Toprak Ahmet Aydogmus (Siber Akademi)
11
+ Version: 10.4.0
12
+ """
13
+
14
+ import os
15
+ import sys
16
+ from typing import Any, Dict, List, Optional
17
+
18
+ from .models import (
19
+ DiagnosticIssue,
20
+ DiagnosticReport,
21
+ HealAction,
22
+ HealReport,
23
+ SeverityLevel,
24
+ )
25
+
26
+
27
+ class InteractiveFixerTUI:
28
+ """Terminal UI renderer for T-Zero Autonomous Doctor."""
29
+
30
+ @staticmethod
31
+ def render_gauge(percentage: int, width: int = 30) -> str:
32
+ """Render a colored ASCII health progress bar gauge."""
33
+ fill = int(width * (percentage / 100))
34
+ empty = width - fill
35
+ if percentage >= 90:
36
+ color = "\033[1;32m" # Bold green
37
+ elif percentage >= 70:
38
+ color = "\033[1;33m" # Bold yellow
39
+ else:
40
+ color = "\033[1;31m" # Bold red
41
+
42
+ bar = "█" * fill + "░" * empty
43
+ return f"{color}[{bar}] {percentage}%\033[0m"
44
+
45
+ @classmethod
46
+ def render_cockpit(cls, diag: DiagnosticReport, heal: Optional[HealReport] = None):
47
+ """Render full interactive cockpit view."""
48
+ term_width = 80
49
+
50
+ print("\033[36m" + "╔" + "═" * (term_width - 2) + "╗\033[0m")
51
+ print("\033[36m║\033[0m\033[1;37m ⚡ T-ZERO AUTONOMOUS PC-FIXER & CODEBASE DOCTOR COCKPIT \033[0m" + " " * 18 + "\033[36m║\033[0m")
52
+ print("\033[36m╠" + "═" * (term_width - 2) + "╣\033[0m")
53
+
54
+ # Top summary row
55
+ gauge = cls.render_gauge(diag.health_score_pct)
56
+ print(f"\033[36m║\033[0m Overall Health: {gauge:<38} \033[36m║\033[0m")
57
+ print(f"\033[36m║\033[0m Directory: \033[33m{diag.target_dir[:58]:<58}\033[0m \033[36m║\033[0m")
58
+ print(f"\033[36m║\033[0m Platform: \033[32m{diag.environment.os_release[:40]:<40}\033[0m (\033[35mv{diag.environment.python_version}\033[0m) \033[36m║\033[0m")
59
+ print(f"\033[36m║\033[0m Hardware: \033[36m{diag.environment.cpu_cores} Cores\033[0m | \033[36m{diag.environment.available_ram_gb:.1f}GB / {diag.environment.total_ram_gb:.1f}GB Free RAM\033[0m" + " " * 15 + "\033[36m║\033[0m")
60
+ print("\033[36m╠" + "═" * (term_width - 2) + "╣\033[0m")
61
+
62
+ # Diagnostics matrix
63
+ print("\033[36m║\033[0m \033[1mDIAGNOSTIC METRICS BREAKDOWN\033[0m" + " " * 48 + "\033[36m║\033[0m")
64
+ print(f"\033[36m║\033[0m • Critical Faults: \033[1;31m{diag.critical_count:<4}\033[0m │ Syntax Defects: \033[31m{diag.syntax_errors:<4}\033[0m \033[36m║\033[0m")
65
+ print(f"\033[36m║\033[0m • Error Level: \033[31m{diag.error_count:<4}\033[0m │ Missing Imports: \033[33m{diag.missing_imports:<4}\033[0m \033[36m║\033[0m")
66
+ print(f"\033[36m║\033[0m • Warnings: \033[33m{diag.warning_count:<4}\033[0m │ Security Leaks: \033[1;31m{diag.security_leaks:<4}\033[0m \033[36m║\033[0m")
67
+ print(f"\033[36m║\033[0m • Code Smells: \033[36m{diag.code_smells:<4}\033[0m │ Cache & Bytecode: \033[32m{diag.cache_issues:<4}\033[0m \033[36m║\033[0m")
68
+ print(f"\033[36m║\033[0m • Scanned Files: \033[35m{diag.scanned_file_count:<4}\033[0m │ Scan Latency: \033[35m{diag.scan_duration_ms}ms\033[0m" + " " * 9 + "\033[36m║\033[0m")
69
+
70
+ # Healing section if present
71
+ if heal:
72
+ print("\033[36m╠" + "═" * (term_width - 2) + "╣\033[0m")
73
+ print("\033[36m║\033[0m \033[1;32m💉 AUTONOMOUS SELF-HEALING OUTCOME\033[0m" + " " * 42 + "\033[36m║\033[0m")
74
+ print(f"\033[36m║\033[0m • Transaction: \033[35m{heal.transaction_id:<32}\033[0m \033[36m║\033[0m")
75
+ print(f"\033[36m║\033[0m • Issues Healed: \033[1;32m{heal.issues_healed} / {heal.issues_detected}\033[0m ({'DRY-RUN PREVIEW' if heal.dry_run else 'COMMITTED TO DISK'}) \033[36m║\033[0m")
76
+ print(f"\033[36m║\033[0m • Score Boost: \033[33m{heal.initial_health_score}%\033[0m -> \033[1;32m{heal.final_health_score}%\033[0m in \033[36m{heal.execution_duration_ms:.1f}ms\033[0m \033[36m║\033[0m")
77
+
78
+ print("\033[36m╚" + "═" * (term_width - 2) + "╝\033[0m")
79
+
80
+ @classmethod
81
+ def render_diff(cls, diff_text: str):
82
+ """Render a unified diff with ANSI syntax colors."""
83
+ for line in diff_text.splitlines():
84
+ if line.startswith("+"):
85
+ print(f"\033[32m{line}\033[0m")
86
+ elif line.startswith("-"):
87
+ print(f"\033[31m{line}\033[0m")
88
+ elif line.startswith("@@"):
89
+ print(f"\033[35m{line}\033[0m")
90
+ else:
91
+ print(line)