kernhell 0.1.0__py3-none-any.whl

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.

Potentially problematic release.


This version of kernhell might be problematic. Click here for more details.

Files changed (42) hide show
  1. kernhell/__init__.py +8 -0
  2. kernhell/__main__.py +6 -0
  3. kernhell/analyzer/analyzer.py +178 -0
  4. kernhell/analyzer/healer.py +249 -0
  5. kernhell/analyzer/prompts.py +89 -0
  6. kernhell/api/__init__.py +5 -0
  7. kernhell/api/server.py +367 -0
  8. kernhell/cache/__init__.py +13 -0
  9. kernhell/cache/cache_manager.py +221 -0
  10. kernhell/cache/embedder.py +104 -0
  11. kernhell/cache/schemas.py +42 -0
  12. kernhell/cli/__init__.py +1 -0
  13. kernhell/cli/app.py +62 -0
  14. kernhell/cli/commands/__init__.py +1 -0
  15. kernhell/cli/commands/cache.py +96 -0
  16. kernhell/cli/commands/config.py +111 -0
  17. kernhell/cli/commands/dashboard.py +55 -0
  18. kernhell/cli/commands/heal.py +141 -0
  19. kernhell/cli/commands/scan.py +87 -0
  20. kernhell/cli/ui.py +176 -0
  21. kernhell/core/__init__.py +1 -0
  22. kernhell/core/config.py +219 -0
  23. kernhell/core/exceptions.py +104 -0
  24. kernhell/core/models.py +174 -0
  25. kernhell/core/orchestrator.py +245 -0
  26. kernhell/patcher/patcher.py +215 -0
  27. kernhell/patcher/verifier.py +82 -0
  28. kernhell/pruner/__init__.py +1 -0
  29. kernhell/pruner/dom_pruner.py +240 -0
  30. kernhell/reporter/__init__.py +5 -0
  31. kernhell/reporter/reporter.py +124 -0
  32. kernhell/scanner/__init__.py +1 -0
  33. kernhell/scanner/parser.py +276 -0
  34. kernhell/scanner/runner.py +242 -0
  35. kernhell/utils/__init__.py +1 -0
  36. kernhell/utils/file_utils.py +117 -0
  37. kernhell/utils/logger.py +78 -0
  38. kernhell-0.1.0.dist-info/METADATA +245 -0
  39. kernhell-0.1.0.dist-info/RECORD +42 -0
  40. kernhell-0.1.0.dist-info/WHEEL +4 -0
  41. kernhell-0.1.0.dist-info/entry_points.txt +2 -0
  42. kernhell-0.1.0.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,242 @@
1
+ """Scanner runner β€” executes Playwright tests and captures failures + live DOM.
2
+
3
+ Weekend 1 strategy: **Subprocess-based** execution.
4
+ 1. Run the test file via ``pytest`` in a subprocess.
5
+ 2. If it fails, parse the error output for broken selectors.
6
+ 3. Re-launch a browser, navigate to the page URL extracted from the test,
7
+ and capture ``page.content()`` for the live DOM snapshot.
8
+
9
+ This approach is simpler but less precise than the step-by-step interceptor
10
+ (planned for Weekend 3). It works reliably for the common case where the
11
+ test navigates to a URL before interacting with elements.
12
+ """
13
+
14
+ from __future__ import annotations
15
+
16
+ import asyncio
17
+ import subprocess
18
+ import re
19
+ import sys
20
+ from pathlib import Path
21
+
22
+ import structlog
23
+
24
+ from kernhell.core.config import KernHellConfig
25
+ from kernhell.core.exceptions import (
26
+ NoFailuresDetectedError,
27
+ PlaywrightNotInstalledError,
28
+ ScannerError,
29
+ TestFileNotFoundError,
30
+ )
31
+ from kernhell.core.models import FailureContext
32
+ from kernhell.scanner.parser import parse_playwright_errors
33
+
34
+ logger = structlog.get_logger()
35
+
36
+
37
+ def _extract_url_from_test(test_file: Path) -> str | None:
38
+ """Extract the first ``page.goto(...)`` URL from a test file.
39
+
40
+ This is a best-effort heuristic used to re-open the page for DOM capture.
41
+ """
42
+ try:
43
+ content = test_file.read_text(encoding="utf-8")
44
+ except Exception:
45
+ return None
46
+
47
+ # Match: page.goto("https://example.com") or page.goto('...')
48
+ m = re.search(r"""page\.goto\(\s*["'](.+?)["']""", content)
49
+ return m.group(1) if m else None
50
+
51
+
52
+ class ScannerRunner:
53
+ """Executes a Playwright test file and captures failure context.
54
+
55
+ Parameters
56
+ ----------
57
+ config:
58
+ The KernHell configuration (scanner timeout, browser, headless, etc.).
59
+ """
60
+
61
+ def __init__(self, config: KernHellConfig) -> None:
62
+ self._config = config
63
+ self._scanner_cfg = config.scanner
64
+
65
+ def run(self, test_file: Path) -> list[FailureContext]:
66
+ """Run the test file and return structured failures.
67
+
68
+ Parameters
69
+ ----------
70
+ test_file:
71
+ Path to the Playwright test file (e.g., ``tests/test_checkout.py``).
72
+
73
+ Returns
74
+ -------
75
+ list[FailureContext]
76
+ One entry per broken selector detected. The ``live_dom`` field
77
+ will be populated if we can successfully re-open the page.
78
+
79
+ Raises
80
+ ------
81
+ TestFileNotFoundError
82
+ If *test_file* does not exist.
83
+ ScannerError
84
+ If the test runner itself fails to execute.
85
+ NoFailuresDetectedError
86
+ If the test passes with zero selector failures.
87
+ """
88
+ test_file = test_file.resolve()
89
+ if not test_file.is_file():
90
+ raise TestFileNotFoundError(f"Test file not found: {test_file}")
91
+
92
+ logger.info("scanner.run.start", test_file=str(test_file))
93
+
94
+ # Step 1: Run the test via pytest subprocess
95
+ error_output = self._run_pytest(test_file)
96
+
97
+ if error_output is None:
98
+ raise NoFailuresDetectedError(
99
+ f"All tests passed in {test_file.name} β€” nothing to heal!"
100
+ )
101
+
102
+ # Step 2: Parse the error output
103
+ failures = parse_playwright_errors(error_output, test_file)
104
+
105
+ if not failures:
106
+ raise NoFailuresDetectedError(
107
+ f"Test failed but no Playwright selector errors detected in {test_file.name}. "
108
+ "The failure may not be selector-related."
109
+ )
110
+
111
+ # Step 3: Capture live DOM for each failure
112
+ page_url = _extract_url_from_test(test_file)
113
+ if page_url:
114
+ live_dom = self._capture_live_dom(page_url)
115
+ if live_dom:
116
+ for f in failures:
117
+ f.live_dom = live_dom
118
+ f.page_url = page_url
119
+
120
+ logger.info(
121
+ "scanner.run.done",
122
+ test_file=str(test_file),
123
+ failures=len(failures),
124
+ has_dom=bool(failures[0].live_dom) if failures else False,
125
+ )
126
+ return failures
127
+
128
+ def _run_pytest(self, test_file: Path) -> str | None:
129
+ """Execute pytest on the test file and return error output.
130
+
131
+ Returns *None* if the test passes (exit code 0).
132
+ """
133
+ cmd = [
134
+ sys.executable,
135
+ "-m",
136
+ "pytest",
137
+ str(test_file),
138
+ "-v",
139
+ "--tb=long",
140
+ "--no-header",
141
+ f"--timeout={self._scanner_cfg.timeout_ms // 1000}",
142
+ ]
143
+
144
+ logger.debug("scanner.pytest.exec", cmd=" ".join(cmd))
145
+
146
+ try:
147
+ result = subprocess.run(
148
+ cmd,
149
+ capture_output=True,
150
+ text=True,
151
+ timeout=self._scanner_cfg.timeout_ms * 3 / 1000, # 3x the action timeout
152
+ cwd=str(test_file.parent),
153
+ )
154
+ except FileNotFoundError:
155
+ raise PlaywrightNotInstalledError(
156
+ "pytest is not installed or not on PATH. "
157
+ "Run: pip install pytest pytest-playwright"
158
+ )
159
+ except subprocess.TimeoutExpired:
160
+ raise ScannerError(
161
+ f"Test execution timed out after {self._scanner_cfg.timeout_ms * 3}ms"
162
+ )
163
+
164
+ if result.returncode == 0:
165
+ logger.info("scanner.pytest.passed", test_file=str(test_file))
166
+ return None
167
+
168
+ # Combine stdout and stderr for full error context
169
+ combined = result.stdout + "\n" + result.stderr
170
+ logger.debug(
171
+ "scanner.pytest.failed",
172
+ exit_code=result.returncode,
173
+ output_len=len(combined),
174
+ )
175
+ return combined
176
+
177
+ def _capture_live_dom(self, url: str) -> str:
178
+ """Re-open the page URL and capture the live DOM HTML.
179
+
180
+ Uses Playwright's sync API to launch a browser, navigate to the URL,
181
+ and grab ``page.content()``. This gives us the actual DOM state
182
+ the developer sees, even if selectors changed.
183
+ """
184
+ try:
185
+ return asyncio.get_event_loop().run_until_complete(
186
+ self._async_capture_dom(url)
187
+ )
188
+ except RuntimeError:
189
+ # No event loop running β€” create one
190
+ return asyncio.run(self._async_capture_dom(url))
191
+
192
+ async def _async_capture_dom(self, url: str) -> str:
193
+ """Async implementation of DOM capture."""
194
+ try:
195
+ from playwright.async_api import async_playwright
196
+ except ImportError:
197
+ raise PlaywrightNotInstalledError(
198
+ "Playwright is not installed. Run: pip install playwright && playwright install"
199
+ )
200
+
201
+ logger.debug("scanner.dom_capture.start", url=url)
202
+
203
+ try:
204
+ async with async_playwright() as p:
205
+ browser_type = getattr(p, self._scanner_cfg.browser, p.chromium)
206
+ browser = await browser_type.launch(headless=self._scanner_cfg.headless)
207
+ page = await browser.new_page()
208
+
209
+ try:
210
+ await page.goto(
211
+ url,
212
+ wait_until="domcontentloaded",
213
+ timeout=self._scanner_cfg.timeout_ms,
214
+ )
215
+ # Wait a bit for dynamic content
216
+ await page.wait_for_timeout(1000)
217
+ dom = await page.content()
218
+
219
+ # Optional screenshot
220
+ if self._scanner_cfg.capture_screenshot:
221
+ screenshot = await page.screenshot(full_page=True)
222
+ logger.debug(
223
+ "scanner.screenshot.captured",
224
+ size=len(screenshot),
225
+ )
226
+
227
+ logger.info(
228
+ "scanner.dom_capture.done",
229
+ url=url,
230
+ dom_size=len(dom),
231
+ )
232
+ return dom
233
+ finally:
234
+ await browser.close()
235
+
236
+ except Exception as exc:
237
+ logger.warning(
238
+ "scanner.dom_capture.failed",
239
+ url=url,
240
+ error=str(exc),
241
+ )
242
+ return ""
@@ -0,0 +1 @@
1
+ """Utility package β€” logging, file I/O, and git helpers."""
@@ -0,0 +1,117 @@
1
+ """Safe file I/O utilities for KernHell.
2
+
3
+ Every file write goes through these helpers so we can:
4
+ - Create automatic backups before patching.
5
+ - Handle encoding consistently (UTF-8 everywhere).
6
+ - Provide atomic writes to prevent half-written files on crash.
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ import os
12
+ import shutil
13
+ import tempfile
14
+ from pathlib import Path
15
+
16
+ import structlog
17
+
18
+ logger = structlog.get_logger()
19
+
20
+
21
+ def read_file(path: Path) -> str:
22
+ """Read a file as UTF-8 text.
23
+
24
+ Raises
25
+ ------
26
+ FileNotFoundError
27
+ If the file does not exist.
28
+ """
29
+ resolved = path.resolve()
30
+ logger.debug("file.read", path=str(resolved))
31
+ return resolved.read_text(encoding="utf-8")
32
+
33
+
34
+ def write_file(path: Path, content: str) -> None:
35
+ """Write content to a file atomically.
36
+
37
+ Writes to a temporary file in the same directory first, then
38
+ atomically replaces the target. This prevents data loss if the
39
+ process crashes mid-write.
40
+ """
41
+ resolved = path.resolve()
42
+ resolved.parent.mkdir(parents=True, exist_ok=True)
43
+
44
+ # Write to a temp file in the same directory so os.replace is atomic.
45
+ fd, tmp_path_str = tempfile.mkstemp(
46
+ dir=str(resolved.parent),
47
+ prefix=".kernhell_",
48
+ suffix=".tmp",
49
+ )
50
+ # Important on Windows: close file descriptor immediately so file isn't locked
51
+ os.close(fd)
52
+ tmp_path = Path(tmp_path_str)
53
+ try:
54
+ tmp_path.write_text(content, encoding="utf-8")
55
+ os.replace(str(tmp_path), str(resolved))
56
+ logger.debug("file.write", path=str(resolved), size=len(content))
57
+ except Exception:
58
+ # Clean up the temp file on failure.
59
+ tmp_path.unlink(missing_ok=True)
60
+ raise
61
+
62
+
63
+ def backup_file(path: Path, suffix: str = ".kernhell.bak") -> Path:
64
+ """Create a backup copy of a file before patching.
65
+
66
+ Returns the path to the backup file.
67
+ """
68
+ resolved = path.resolve()
69
+ backup_path = resolved.with_suffix(resolved.suffix + suffix)
70
+ shutil.copy2(str(resolved), str(backup_path))
71
+ logger.info("file.backup", original=str(resolved), backup=str(backup_path))
72
+ return backup_path
73
+
74
+
75
+ def restore_from_backup(original: Path, suffix: str = ".kernhell.bak") -> bool:
76
+ """Restore a file from its backup. Returns True if successful."""
77
+ resolved = original.resolve()
78
+ backup_path = resolved.with_suffix(resolved.suffix + suffix)
79
+ if backup_path.is_file():
80
+ shutil.copy2(str(backup_path), str(resolved))
81
+ logger.info("file.restore", path=str(resolved))
82
+ return True
83
+ logger.warning("file.restore.missing", backup=str(backup_path))
84
+ return False
85
+
86
+
87
+ def extract_surrounding_lines(
88
+ content: str,
89
+ line_number: int,
90
+ context: int = 10,
91
+ ) -> str:
92
+ """Extract Β±context lines around a specific line number.
93
+
94
+ Parameters
95
+ ----------
96
+ content:
97
+ Full file content.
98
+ line_number:
99
+ 1-indexed line number to centre on.
100
+ context:
101
+ Number of lines to include above and below.
102
+
103
+ Returns
104
+ -------
105
+ str
106
+ The extracted lines with line numbers prefixed.
107
+ """
108
+ lines = content.splitlines()
109
+ start = max(0, line_number - 1 - context)
110
+ end = min(len(lines), line_number + context)
111
+
112
+ numbered: list[str] = []
113
+ for i, line in enumerate(lines[start:end], start=start + 1):
114
+ marker = " >>> " if i == line_number else " "
115
+ numbered.append(f"{i:4d}{marker}{line}")
116
+
117
+ return "\n".join(numbered)
@@ -0,0 +1,78 @@
1
+ """Structured logging configuration for KernHell.
2
+
3
+ Uses ``structlog`` with two output modes:
4
+ - **Console** (default): Rich-coloured, human-friendly output via
5
+ ``structlog.dev.ConsoleRenderer``.
6
+ - **JSON** (``--json-log`` or CI): Machine-parseable JSON lines, ideal
7
+ for log aggregation.
8
+
9
+ Call :func:`setup_logging` once at startup (done automatically by the CLI).
10
+ After that, obtain loggers anywhere with ``structlog.get_logger()``.
11
+ """
12
+
13
+ from __future__ import annotations
14
+
15
+ import logging
16
+ import sys
17
+
18
+ import structlog
19
+
20
+
21
+ def setup_logging(*, level: str = "INFO", json_output: bool = False) -> None:
22
+ """Configure structlog and stdlib logging for the application.
23
+
24
+ Parameters
25
+ ----------
26
+ level:
27
+ Minimum log level (``DEBUG``, ``INFO``, ``WARNING``, ``ERROR``).
28
+ json_output:
29
+ When *True*, emit JSON lines instead of coloured console output.
30
+ Recommended for CI/CD environments.
31
+ """
32
+ log_level = getattr(logging, level.upper(), logging.INFO)
33
+
34
+ # Shared processors run before the final renderer.
35
+ shared_processors: list[structlog.types.Processor] = [
36
+ structlog.contextvars.merge_contextvars,
37
+ structlog.stdlib.add_log_level,
38
+ structlog.stdlib.add_logger_name,
39
+ structlog.processors.TimeStamper(fmt="iso"),
40
+ structlog.processors.StackInfoRenderer(),
41
+ structlog.processors.UnicodeDecoder(),
42
+ ]
43
+
44
+ if json_output:
45
+ renderer: structlog.types.Processor = structlog.processors.JSONRenderer()
46
+ else:
47
+ renderer = structlog.dev.ConsoleRenderer(
48
+ colors=sys.stderr.isatty(),
49
+ )
50
+
51
+ structlog.configure(
52
+ processors=[
53
+ *shared_processors,
54
+ structlog.stdlib.ProcessorFormatter.wrap_for_formatter,
55
+ ],
56
+ logger_factory=structlog.stdlib.LoggerFactory(),
57
+ wrapper_class=structlog.stdlib.BoundLogger,
58
+ cache_logger_on_first_use=True,
59
+ )
60
+
61
+ formatter = structlog.stdlib.ProcessorFormatter(
62
+ processors=[
63
+ structlog.stdlib.ProcessorFormatter.remove_processors_meta,
64
+ renderer,
65
+ ],
66
+ )
67
+
68
+ handler = logging.StreamHandler(sys.stderr)
69
+ handler.setFormatter(formatter)
70
+
71
+ root = logging.getLogger()
72
+ root.handlers.clear()
73
+ root.addHandler(handler)
74
+ root.setLevel(log_level)
75
+
76
+ # Silence noisy third-party loggers.
77
+ for noisy in ("playwright", "urllib3", "httpx", "chromadb"):
78
+ logging.getLogger(noisy).setLevel(logging.WARNING)
@@ -0,0 +1,245 @@
1
+ Metadata-Version: 2.5
2
+ Name: kernhell
3
+ Version: 0.1.0
4
+ Summary: AI-Powered Autonomous Self-Healing Testing Engine β€” The Heart of Your System Where Innovation Meets Precision
5
+ Project-URL: Homepage, https://github.com/riteshkumar072/KernHell
6
+ Project-URL: Documentation, https://github.com/riteshkumar072/KernHell#readme
7
+ Project-URL: Repository, https://github.com/riteshkumar072/KernHell
8
+ Project-URL: Issues, https://github.com/riteshkumar072/KernHell/issues
9
+ Author-email: Ritesh <ritesh@kernhell.dev>
10
+ License-Expression: MIT
11
+ License-File: LICENSE
12
+ Keywords: ai,cli,playwright,self-healing,testing
13
+ Classifier: Development Status :: 3 - Alpha
14
+ Classifier: Environment :: Console
15
+ Classifier: Intended Audience :: Developers
16
+ Classifier: License :: OSI Approved :: MIT License
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Topic :: Software Development :: Quality Assurance
20
+ Classifier: Topic :: Software Development :: Testing
21
+ Requires-Python: >=3.11
22
+ Requires-Dist: libcst>=1.1.0
23
+ Requires-Dist: litellm<2.0,>=1.30
24
+ Requires-Dist: playwright<2.0,>=1.40
25
+ Requires-Dist: pydantic-settings<3.0,>=2.1
26
+ Requires-Dist: pydantic<3.0,>=2.5
27
+ Requires-Dist: rich<16.0,>=13.0
28
+ Requires-Dist: selectolax<1.0,>=0.3
29
+ Requires-Dist: structlog>=24.0
30
+ Requires-Dist: tomli>=2.0; python_version < '3.11'
31
+ Requires-Dist: typer<1.0,>=0.12
32
+ Provides-Extra: all
33
+ Requires-Dist: aiosqlite<1.0,>=0.19; extra == 'all'
34
+ Requires-Dist: build>=1.0.0; extra == 'all'
35
+ Requires-Dist: chromadb<1.0,>=0.4; extra == 'all'
36
+ Requires-Dist: fastapi<1.0,>=0.110; extra == 'all'
37
+ Requires-Dist: mypy<2.0,>=1.8; extra == 'all'
38
+ Requires-Dist: pytest-asyncio<1.0,>=0.23; extra == 'all'
39
+ Requires-Dist: pytest-cov<6.0,>=5.0; extra == 'all'
40
+ Requires-Dist: pytest<9.0,>=8.0; extra == 'all'
41
+ Requires-Dist: ruff<1.0,>=0.3; extra == 'all'
42
+ Requires-Dist: sentence-transformers<3.0,>=2.2; extra == 'all'
43
+ Requires-Dist: twine>=5.0.0; extra == 'all'
44
+ Requires-Dist: uvicorn[standard]<1.0,>=0.27; extra == 'all'
45
+ Provides-Extra: cache
46
+ Requires-Dist: chromadb<1.0,>=0.4; extra == 'cache'
47
+ Requires-Dist: sentence-transformers<3.0,>=2.2; extra == 'cache'
48
+ Provides-Extra: dashboard
49
+ Requires-Dist: aiosqlite<1.0,>=0.19; extra == 'dashboard'
50
+ Requires-Dist: fastapi<1.0,>=0.110; extra == 'dashboard'
51
+ Requires-Dist: uvicorn[standard]<1.0,>=0.27; extra == 'dashboard'
52
+ Provides-Extra: dev
53
+ Requires-Dist: build>=1.0.0; extra == 'dev'
54
+ Requires-Dist: mypy<2.0,>=1.8; extra == 'dev'
55
+ Requires-Dist: pytest-asyncio<1.0,>=0.23; extra == 'dev'
56
+ Requires-Dist: pytest-cov<6.0,>=5.0; extra == 'dev'
57
+ Requires-Dist: pytest<9.0,>=8.0; extra == 'dev'
58
+ Requires-Dist: ruff<1.0,>=0.3; extra == 'dev'
59
+ Requires-Dist: twine>=5.0.0; extra == 'dev'
60
+ Description-Content-Type: text/markdown
61
+
62
+ # πŸ”₯ KernHell
63
+
64
+ > *"The Heart of Your System Where Innovation Meets Precision"*
65
+
66
+ **AI-Powered Autonomous Self-Healing Testing Engine & CLI tool for Playwright.**
67
+
68
+ [![Python 3.11+](https://img.shields.io/badge/python-3.11+-blue.svg)](https://www.python.org/)
69
+ [![Next.js 14](https://img.shields.io/badge/dashboard-Next.js%2014-black.svg)](https://nextjs.org/)
70
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
71
+ [![CI/CD Status](https://img.shields.io/badge/tests-59%20passed%20(100%25)-brightgreen.svg)](https://github.com/riteshkumar072/KernHell)
72
+
73
+ ---
74
+
75
+ ## ⚑ The Problem
76
+
77
+ Modern frontend engineering moves fast. When developers refactor classes, IDs, or DOM wrappers (e.g., `#buy-now` becomes `#purchase-btn`), automated Playwright and Selenium test suites fail even though the business functionality works seamlessly. QA teams waste 30–40% of their time manually maintaining broken selectors.
78
+
79
+ **KernHell autonomously resolves broken selectors in real-time, preserving 100% of your code formatting, comments, and QA sanity.**
80
+
81
+ ---
82
+
83
+ ## πŸ›οΈ Autonomous 6-Stage Healing Architecture
84
+
85
+ ```mermaid
86
+ flowchart TD
87
+ A[Playwright Locator Timeout] -->|1. Intercept| B(Scanner & Live DOM Capture)
88
+ B -->|2. Prune| C(Selectolax Lexbor HTML5 Pruner)
89
+ C -->|85% Token Reduction| D{3. Dense Vector Cache}
90
+ D -->|Cache Hit <5ms| G[Strict DOM Verification]
91
+ D -->|Cache Miss| E[4. AI Brain: LiteLLM Gateway]
92
+ E -->|Intent Diagnosis| F{RENAME vs MISSING?}
93
+ F -->|MISSING: Real Bug| H[Anti-Hallucination Guardrail: Abort Healing]
94
+ F -->|RENAME: Safe Refactor| G
95
+ G -->|5. Verify Unambiguous Element| I[Selector Fix: role / data-testid / text]
96
+ I -->|Store Embedding| D
97
+ I -->|6. Surgical Patch| J[LibCST AST Patcher]
98
+ J -->|Preserve Comments & Formatting| K[Automatic Verification Runner]
99
+ K -->|Pass| L[Commit Fix & Log Run]
100
+ K -->|Fail| M[Immediate Rollback from .kernhell.bak]
101
+ ```
102
+
103
+ ---
104
+
105
+ ## πŸš€ Key Features
106
+
107
+ - **Failure Interception & Live DOM Capture (`Scanner`)**: Intercepts Playwright selector timeouts and crashes, capturing the error stack trace, line number, broken selector, and live DOM snapshot (`page.content()`).
108
+ - **High-Speed Semantic DOM Pruning (`DOMPruner`)**: Strips scripts, styles, SVGs, base64 data, and non-semantic wrappers using `selectolax` to slash token usage by 80–90% while keeping semantic landmarks and accessibility roles.
109
+ - **Semantic Vector Memory (`Vector Cache`)**: 384-dimensional dense cosine index matching broken selectors against historical fixes. Resolves recurring failures in **<5ms** with zero LLM API cost.
110
+ - **Strict Anti-Hallucination Guardrails**: Distinguishes between renamed selectors (`RENAME`) and genuine missing features (`MISSING`) to prevent false-positive heals on actual product regressions.
111
+ - **Surgical LibCST AST Patching (`Patcher`)**: Surgically transforms only the target locator expression in the AST without reformatting unrelated code or stripping inline comments.
112
+ - **Automated Verification & Zero-Risk Rollback (`Verifier`)**: Re-runs the patched test in a sandbox; if it fails, immediately restores the code from `.kernhell.bak`.
113
+ - **Mission Control Dashboard (`Next.js App Router`)**: High-tech, dark-mode glassmorphic web dashboard providing live stats, real-time healing stream, semantic memory inspector, and interactive simulation playground.
114
+
115
+ ---
116
+
117
+ ## πŸ“¦ Installation
118
+
119
+ ```bash
120
+ # Clone the repository
121
+ git clone https://github.com/riteshkumar072/KernHell.git
122
+ cd KernHell
123
+
124
+ # Install Python package in editable mode with all dependencies
125
+ pip install -e ".[all]"
126
+
127
+ # Install Mission Control dashboard dependencies
128
+ cd dashboard
129
+ npm install
130
+ cd ..
131
+ ```
132
+
133
+ ---
134
+
135
+ ## πŸ› οΈ CLI Usage
136
+
137
+ ```text
138
+ Usage: kernhell [OPTIONS] COMMAND [ARGS]...
139
+
140
+ β”Œβ”€ Commands ──────────────────────────────────────────────────────────────────┐
141
+ β”‚ scan Scan a test file to detect broken selectors and capture DOM β”‚
142
+ β”‚ snapshots. β”‚
143
+ β”‚ heal Autonomously heal broken Playwright selectors in a test file. β”‚
144
+ β”‚ dashboard Launch the KernHell Mission Control Dashboard and REST API. β”‚
145
+ β”‚ ui Alias for 'dashboard' command. β”‚
146
+ β”‚ cache Inspect, query, and manage KernHell's Semantic Vector Cache. β”‚
147
+ β”‚ config View and configure KernHell engine parameters. β”‚
148
+ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
149
+ ```
150
+
151
+ ### 1. Scan a Test File for Broken Selectors
152
+
153
+ ```bash
154
+ kernhell scan tests/test_checkout.py
155
+ ```
156
+
157
+ ### 2. Autonomously Heal a Test File or Suite
158
+
159
+ ```bash
160
+ # Preview changes without modifying code (dry run)
161
+ kernhell heal tests/test_checkout.py --dry-run
162
+
163
+ # Surgically patch and verify fix with automatic backup
164
+ kernhell heal tests/test_checkout.py
165
+
166
+ # Batch heal all test files in a folder
167
+ kernhell heal tests/
168
+
169
+ # Export machine-readable report for CI/CD pipelines
170
+ kernhell heal tests/ --output json
171
+ ```
172
+
173
+ ### 3. Launch the Mission Control Dashboard
174
+
175
+ ```bash
176
+ # Start FastAPI REST API and open dashboard in browser
177
+ kernhell dashboard
178
+
179
+ # Or run Next.js frontend directly:
180
+ cd dashboard
181
+ npm run dev
182
+ ```
183
+
184
+ Visit **`http://localhost:3000`** to view the live dashboard and interactive playground.
185
+
186
+ ### 4. Semantic Vector Memory & Cache
187
+
188
+ ```bash
189
+ # List all verified cached selector mappings
190
+ kernhell cache list
191
+
192
+ # View cache hit/miss ratio and efficiency metrics
193
+ kernhell cache stats
194
+
195
+ # Purge semantic memory
196
+ kernhell cache clear
197
+ ```
198
+
199
+ ### 5. Engine Configuration
200
+
201
+ ```bash
202
+ # Display active settings
203
+ kernhell config show
204
+
205
+ # Run the interactive configuration wizard
206
+ kernhell config init
207
+ ```
208
+
209
+ ---
210
+
211
+ ## πŸ–₯️ Mission Control Dashboard
212
+
213
+ The dashboard provides a production-grade operations center:
214
+
215
+ - **Overview (`/`)**: Real-time healing metrics (autonomous fixes, cache efficiency, real bugs guarded, dollar savings), live 6-stage pipeline status, and recent activity stream.
216
+ - **Interactive Playground (`/playground`)**: Test healer sandbox with pre-configured refactor scenarios and out-of-stock guardrail alerts.
217
+ - **Semantic Memory Explorer (`/cache`)**: Searchable browser for 384-dimensional dense vector embeddings with hit counts and verification badges.
218
+ - **Run History & Diffs (`/history`)**: Audit trail with side-by-side syntax-highlighted unified diffs of AST code patches.
219
+
220
+ ---
221
+
222
+ ## πŸ§ͺ Running the Test Suite
223
+
224
+ ```bash
225
+ # Run all 59 unit and integration tests
226
+ python -m pytest -v
227
+
228
+ # Run with test coverage
229
+ python -m pytest tests/unit -v --cov=src/kernhell
230
+ ```
231
+
232
+ ---
233
+
234
+ ## πŸ—ΊοΈ Execution Roadmap
235
+
236
+ - [x] **Weekend 1: Foundation (Scanner, Pruner, Core Models & CLI)**
237
+ - [x] **Weekend 2: AI Brain (Analyzer, Healer, CST Surgical Patcher & Verifier)**
238
+ - [x] **Weekend 3: Semantic Memory (Vector Cache, Embedder, Batch Healing & CI Export)**
239
+ - [x] **Weekend 4: Mission Control Dashboard (Next.js & Production Release)**
240
+
241
+ ---
242
+
243
+ ## πŸ“„ License
244
+
245
+ MIT &copy; 2026 Ritesh Kumar β€’ KernHell Systems