hyperflash 1.0.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.
- hyperflash/__init__.py +29 -0
- hyperflash/cli.py +303 -0
- hyperflash/core.py +419 -0
- hyperflash/mcp_server.py +342 -0
- hyperflash/polyglot.py +240 -0
- hyperflash-1.0.0.dist-info/METADATA +663 -0
- hyperflash-1.0.0.dist-info/RECORD +11 -0
- hyperflash-1.0.0.dist-info/WHEEL +5 -0
- hyperflash-1.0.0.dist-info/entry_points.txt +2 -0
- hyperflash-1.0.0.dist-info/licenses/LICENSE +21 -0
- hyperflash-1.0.0.dist-info/top_level.txt +1 -0
hyperflash/core.py
ADDED
|
@@ -0,0 +1,419 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Core HyperFlash runtime logic: invariant enforcement, AST symbol graph generation,
|
|
3
|
+
contract state management, and hierarchical verification runner.
|
|
4
|
+
"""
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
import ast
|
|
8
|
+
import json
|
|
9
|
+
import py_compile
|
|
10
|
+
import re
|
|
11
|
+
import shutil
|
|
12
|
+
import subprocess
|
|
13
|
+
import time
|
|
14
|
+
from pathlib import Path
|
|
15
|
+
from typing import Any
|
|
16
|
+
|
|
17
|
+
BANNED_ELISION_PATTERNS: list[str] = [
|
|
18
|
+
r"//\s*\.\.\.\s*(rest|existing|unchanged|remaining|code)",
|
|
19
|
+
r"#\s*\.\.\.\s*(rest|existing|unchanged|remaining|code)",
|
|
20
|
+
r"/\*\s*\.\.\.\s*.*?\*/",
|
|
21
|
+
r"TODO:\s*implement",
|
|
22
|
+
r"//\s*\.\.\.\s*$",
|
|
23
|
+
r"#\s*\.\.\.\s*$",
|
|
24
|
+
r"/\*\s*existing code.*?\*/",
|
|
25
|
+
r"<!--\s*\.\.\.\s*-->",
|
|
26
|
+
]
|
|
27
|
+
|
|
28
|
+
IGNORE_DIRS: set[str] = {
|
|
29
|
+
".git",
|
|
30
|
+
".agents",
|
|
31
|
+
"node_modules",
|
|
32
|
+
"__pycache__",
|
|
33
|
+
".venv",
|
|
34
|
+
"venv",
|
|
35
|
+
"build",
|
|
36
|
+
"dist",
|
|
37
|
+
".pytest_cache",
|
|
38
|
+
".ruff_cache",
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
DEFAULT_CONTRACT: dict[str, Any] = {
|
|
42
|
+
"mode": "implement",
|
|
43
|
+
"effort_profile": "balanced",
|
|
44
|
+
"planning": "compact",
|
|
45
|
+
"context_depth": "dependency",
|
|
46
|
+
"verification_depth": "impact",
|
|
47
|
+
"delegation": "conditional",
|
|
48
|
+
"reason_codes": [],
|
|
49
|
+
"allowed_write_scope": [],
|
|
50
|
+
"acceptance_criteria": [],
|
|
51
|
+
"files_read_in_session": [],
|
|
52
|
+
"last_mutation_ts": 0.0,
|
|
53
|
+
"last_verified_ts": 0.0,
|
|
54
|
+
"last_verdict": "PENDING",
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def check_for_elision(text: str) -> tuple[bool, str]:
|
|
59
|
+
"""
|
|
60
|
+
Scans text for prohibited lazy truncation and placeholder patterns.
|
|
61
|
+
|
|
62
|
+
Returns:
|
|
63
|
+
tuple[bool, str]: (True, matched_pattern) if elision found, else (False, "")
|
|
64
|
+
"""
|
|
65
|
+
for pattern in BANNED_ELISION_PATTERNS:
|
|
66
|
+
match = re.search(pattern, text, re.IGNORECASE | re.MULTILINE)
|
|
67
|
+
if match:
|
|
68
|
+
return True, match.group(0)
|
|
69
|
+
return False, ""
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def enforce_elision_guard(text: str) -> None:
|
|
73
|
+
"""
|
|
74
|
+
Raises ValueError if prohibited elision patterns are detected in the given text.
|
|
75
|
+
"""
|
|
76
|
+
has_elision, pattern = check_for_elision(text)
|
|
77
|
+
if has_elision:
|
|
78
|
+
raise ValueError(
|
|
79
|
+
f"Invariant 7 Violation (Code Truncation Blocked): Prohibited elision pattern '{pattern}' detected. "
|
|
80
|
+
"HyperFlash requires 100% complete, fully implemented code with zero shortcuts."
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def index_python_source(source_code: str, file_label: str = "<source>") -> dict[str, Any]:
|
|
85
|
+
"""
|
|
86
|
+
Parses Python source code into an AST and extracts structured symbol metadata.
|
|
87
|
+
"""
|
|
88
|
+
try:
|
|
89
|
+
tree = ast.parse(source_code, filename=file_label)
|
|
90
|
+
except SyntaxError:
|
|
91
|
+
return {}
|
|
92
|
+
|
|
93
|
+
symbols: dict[str, Any] = {
|
|
94
|
+
"classes": {},
|
|
95
|
+
"functions": [],
|
|
96
|
+
"imports": [],
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
for node in tree.body:
|
|
100
|
+
if isinstance(node, (ast.Import, ast.ImportFrom)):
|
|
101
|
+
try:
|
|
102
|
+
symbols["imports"].append(ast.unparse(node))
|
|
103
|
+
except Exception:
|
|
104
|
+
pass
|
|
105
|
+
elif isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef)):
|
|
106
|
+
args: list[str] = [a.arg for a in node.args.args]
|
|
107
|
+
ret_type: str = "Untyped"
|
|
108
|
+
if node.returns is not None:
|
|
109
|
+
try:
|
|
110
|
+
ret_type = ast.unparse(node.returns)
|
|
111
|
+
except Exception:
|
|
112
|
+
ret_type = "Complex"
|
|
113
|
+
prefix: str = "async def" if isinstance(node, ast.AsyncFunctionDef) else "def"
|
|
114
|
+
symbols["functions"].append(
|
|
115
|
+
f"L{node.lineno}: {prefix} {node.name}({', '.join(args)}) -> {ret_type}"
|
|
116
|
+
)
|
|
117
|
+
elif isinstance(node, ast.ClassDef):
|
|
118
|
+
methods: list[str] = []
|
|
119
|
+
for item in node.body:
|
|
120
|
+
if isinstance(item, (ast.FunctionDef, ast.AsyncFunctionDef)):
|
|
121
|
+
m_prefix: str = "async " if isinstance(item, ast.AsyncFunctionDef) else ""
|
|
122
|
+
m_args: list[str] = [a.arg for a in item.args.args]
|
|
123
|
+
m_ret: str = "Untyped"
|
|
124
|
+
if item.returns is not None:
|
|
125
|
+
try:
|
|
126
|
+
m_ret = ast.unparse(item.returns)
|
|
127
|
+
except Exception:
|
|
128
|
+
m_ret = "Complex"
|
|
129
|
+
methods.append(f"L{item.lineno}:{m_prefix}{item.name}({', '.join(m_args)}) -> {m_ret}")
|
|
130
|
+
symbols["classes"][f"L{node.lineno}:{node.name}"] = methods
|
|
131
|
+
|
|
132
|
+
return {k: v for k, v in symbols.items() if v}
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def index_python_file(path: Path) -> dict[str, Any]:
|
|
136
|
+
"""
|
|
137
|
+
Indexes a single Python file on disk into symbol metadata.
|
|
138
|
+
"""
|
|
139
|
+
if not path.is_file():
|
|
140
|
+
return {}
|
|
141
|
+
try:
|
|
142
|
+
content: str = path.read_text(encoding="utf-8", errors="ignore")
|
|
143
|
+
return index_python_source(content, str(path))
|
|
144
|
+
except Exception:
|
|
145
|
+
return {}
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
def generate_symbol_graph(root_dir: Path | str = ".") -> dict[str, dict[str, Any]]:
|
|
149
|
+
"""
|
|
150
|
+
Crawls root_dir and indexes all Python files into an AST symbol graph.
|
|
151
|
+
"""
|
|
152
|
+
base_path = Path(root_dir).resolve()
|
|
153
|
+
graph: dict[str, dict[str, Any]] = {}
|
|
154
|
+
|
|
155
|
+
if not base_path.exists():
|
|
156
|
+
return graph
|
|
157
|
+
|
|
158
|
+
for py_file in base_path.rglob("*.py"):
|
|
159
|
+
if any(part in IGNORE_DIRS for part in py_file.parts):
|
|
160
|
+
continue
|
|
161
|
+
info = index_python_file(py_file)
|
|
162
|
+
if info:
|
|
163
|
+
try:
|
|
164
|
+
rel_path = py_file.relative_to(base_path).as_posix()
|
|
165
|
+
except ValueError:
|
|
166
|
+
rel_path = py_file.as_posix()
|
|
167
|
+
graph[rel_path] = info
|
|
168
|
+
|
|
169
|
+
return graph
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
def build_symbol_graph(
|
|
173
|
+
root_dir: Path | str = ".",
|
|
174
|
+
output_file: Path | str = ".agents/state/symbol_graph.json",
|
|
175
|
+
) -> dict[str, dict[str, Any]]:
|
|
176
|
+
"""
|
|
177
|
+
Generates symbol graph and writes it to output_file on disk.
|
|
178
|
+
"""
|
|
179
|
+
base_path = Path(root_dir)
|
|
180
|
+
out_path = Path(output_file) if Path(output_file).is_absolute() else base_path / output_file
|
|
181
|
+
graph = generate_symbol_graph(base_path)
|
|
182
|
+
|
|
183
|
+
out_path.parent.mkdir(parents=True, exist_ok=True)
|
|
184
|
+
out_path.write_text(json.dumps(graph, indent=2), encoding="utf-8")
|
|
185
|
+
return graph
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
def load_contract(
|
|
189
|
+
contract_path: Path | str = ".agents/state/contract.json",
|
|
190
|
+
) -> dict[str, Any]:
|
|
191
|
+
"""
|
|
192
|
+
Loads contract state safely from JSON file, returning DEFAULT_CONTRACT on error.
|
|
193
|
+
"""
|
|
194
|
+
path = Path(contract_path)
|
|
195
|
+
if not path.is_file():
|
|
196
|
+
return dict(DEFAULT_CONTRACT)
|
|
197
|
+
try:
|
|
198
|
+
data = json.loads(path.read_text(encoding="utf-8"))
|
|
199
|
+
merged = dict(DEFAULT_CONTRACT)
|
|
200
|
+
merged.update(data)
|
|
201
|
+
return merged
|
|
202
|
+
except Exception:
|
|
203
|
+
return dict(DEFAULT_CONTRACT)
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
def save_contract(
|
|
207
|
+
contract_data: dict[str, Any],
|
|
208
|
+
contract_path: Path | str = ".agents/state/contract.json",
|
|
209
|
+
) -> None:
|
|
210
|
+
"""
|
|
211
|
+
Safely serializes and saves contract data to contract_path.
|
|
212
|
+
"""
|
|
213
|
+
path = Path(contract_path)
|
|
214
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
215
|
+
path.write_text(json.dumps(contract_data, indent=2), encoding="utf-8")
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
def run_cmd(cmd: list[str], cwd: Path, timeout: int = 120) -> tuple[int, str]:
|
|
219
|
+
"""
|
|
220
|
+
Executes a shell command safely, capturing stdout and stderr.
|
|
221
|
+
"""
|
|
222
|
+
try:
|
|
223
|
+
res = subprocess.run(
|
|
224
|
+
cmd,
|
|
225
|
+
cwd=str(cwd),
|
|
226
|
+
capture_output=True,
|
|
227
|
+
text=True,
|
|
228
|
+
timeout=timeout,
|
|
229
|
+
)
|
|
230
|
+
combined: str = (res.stdout + "\n" + res.stderr).strip()
|
|
231
|
+
truncated: str = combined[-4000:] if len(combined) > 4000 else combined
|
|
232
|
+
return res.returncode, truncated
|
|
233
|
+
except Exception as exc:
|
|
234
|
+
return 1, str(exc)
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
def run_verification(
|
|
238
|
+
tier: int | None = None,
|
|
239
|
+
custom_cmd: str = "",
|
|
240
|
+
workspace_dir: Path | str = ".",
|
|
241
|
+
) -> dict[str, Any]:
|
|
242
|
+
"""
|
|
243
|
+
Executes the HyperFlash deterministic verification hierarchy and updates contract.json.
|
|
244
|
+
"""
|
|
245
|
+
workspace = Path(workspace_dir).resolve()
|
|
246
|
+
contract_path = workspace / ".agents/state/contract.json"
|
|
247
|
+
diagnostics: list[dict[str, Any]] = []
|
|
248
|
+
passed_all: bool = True
|
|
249
|
+
|
|
250
|
+
def tier_active(t: int) -> bool:
|
|
251
|
+
return tier is None or t <= tier
|
|
252
|
+
|
|
253
|
+
# Gather Python source files
|
|
254
|
+
py_files: list[Path] = [
|
|
255
|
+
p for p in workspace.rglob("*.py")
|
|
256
|
+
if not any(part in IGNORE_DIRS for part in p.parts)
|
|
257
|
+
]
|
|
258
|
+
|
|
259
|
+
# Tier 1: Syntax Integrity (py_compile)
|
|
260
|
+
if tier_active(1) and py_files:
|
|
261
|
+
for py_f in py_files:
|
|
262
|
+
try:
|
|
263
|
+
py_compile.compile(str(py_f), doraise=True)
|
|
264
|
+
except py_compile.PyCompileError as err:
|
|
265
|
+
passed_all = False
|
|
266
|
+
diagnostics.append({
|
|
267
|
+
"tier": 1,
|
|
268
|
+
"name": "syntax_integrity",
|
|
269
|
+
"tool": "py_compile",
|
|
270
|
+
"file": str(py_f.relative_to(workspace) if py_f.is_relative_to(workspace) else py_f),
|
|
271
|
+
"error": str(err),
|
|
272
|
+
})
|
|
273
|
+
|
|
274
|
+
# Tier 3: Static Type Soundness (tsc / mypy)
|
|
275
|
+
if tier_active(3):
|
|
276
|
+
tsconfig = workspace / "tsconfig.json"
|
|
277
|
+
if tsconfig.exists() and shutil.which("npx"):
|
|
278
|
+
code, out = run_cmd(["npx", "tsc", "--noEmit"], cwd=workspace)
|
|
279
|
+
diagnostics.append({
|
|
280
|
+
"tier": 3,
|
|
281
|
+
"name": "type_soundness",
|
|
282
|
+
"tool": "tsc",
|
|
283
|
+
"exit_code": code,
|
|
284
|
+
"output": out,
|
|
285
|
+
})
|
|
286
|
+
if code != 0:
|
|
287
|
+
passed_all = False
|
|
288
|
+
|
|
289
|
+
# Tier 5: Static Analysis / Linting (ruff)
|
|
290
|
+
if tier_active(5) and py_files and shutil.which("ruff"):
|
|
291
|
+
code, out = run_cmd(["ruff", "check", "."], cwd=workspace)
|
|
292
|
+
diagnostics.append({
|
|
293
|
+
"tier": 5,
|
|
294
|
+
"name": "static_analysis",
|
|
295
|
+
"tool": "ruff",
|
|
296
|
+
"exit_code": code,
|
|
297
|
+
"output": out,
|
|
298
|
+
})
|
|
299
|
+
if code != 0:
|
|
300
|
+
passed_all = False
|
|
301
|
+
|
|
302
|
+
# Tier 6: Workspace Test Suite (pytest)
|
|
303
|
+
has_py_tests = any(p.name.startswith("test_") or p.name.endswith("_test.py") for p in py_files)
|
|
304
|
+
if tier_active(6) and has_py_tests and shutil.which("pytest"):
|
|
305
|
+
code, out = run_cmd(["pytest", "-q", "--tb=short"], cwd=workspace)
|
|
306
|
+
diagnostics.append({
|
|
307
|
+
"tier": 6,
|
|
308
|
+
"name": "workspace_test_suite",
|
|
309
|
+
"tool": "pytest",
|
|
310
|
+
"exit_code": code,
|
|
311
|
+
"output": out,
|
|
312
|
+
})
|
|
313
|
+
if code != 0:
|
|
314
|
+
passed_all = False
|
|
315
|
+
|
|
316
|
+
# Custom Command if provided
|
|
317
|
+
if custom_cmd:
|
|
318
|
+
code, out = run_cmd(custom_cmd.split(), cwd=workspace)
|
|
319
|
+
diagnostics.append({
|
|
320
|
+
"tier": 0,
|
|
321
|
+
"name": "custom_validator",
|
|
322
|
+
"command": custom_cmd,
|
|
323
|
+
"exit_code": code,
|
|
324
|
+
"output": out,
|
|
325
|
+
})
|
|
326
|
+
if code != 0:
|
|
327
|
+
passed_all = False
|
|
328
|
+
|
|
329
|
+
verdict_str: str = "VERDICT: PASS" if passed_all else "VERDICT: FAIL -- Verification checks failed"
|
|
330
|
+
|
|
331
|
+
# Update contract state
|
|
332
|
+
contract = load_contract(contract_path)
|
|
333
|
+
if passed_all:
|
|
334
|
+
contract["last_verified_ts"] = time.time()
|
|
335
|
+
contract["last_verdict"] = "PASS"
|
|
336
|
+
else:
|
|
337
|
+
contract["last_verdict"] = "FAIL"
|
|
338
|
+
save_contract(contract, contract_path)
|
|
339
|
+
|
|
340
|
+
return {
|
|
341
|
+
"verdict": verdict_str,
|
|
342
|
+
"passed": passed_all,
|
|
343
|
+
"diagnostics": diagnostics,
|
|
344
|
+
"timestamp": time.time(),
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
|
|
348
|
+
class HyperFlashRuntime:
|
|
349
|
+
"""
|
|
350
|
+
High-level API for interacting with HyperFlash runtime within Python.
|
|
351
|
+
"""
|
|
352
|
+
|
|
353
|
+
def __init__(self, workspace_dir: Path | str = ".") -> None:
|
|
354
|
+
self.workspace_dir: Path = Path(workspace_dir).resolve()
|
|
355
|
+
self.contract_path: Path = self.workspace_dir / ".agents/state/contract.json"
|
|
356
|
+
self.symbol_graph_path: Path = self.workspace_dir / ".agents/state/symbol_graph.json"
|
|
357
|
+
|
|
358
|
+
def get_contract(self) -> dict[str, Any]:
|
|
359
|
+
"""Returns active contract state."""
|
|
360
|
+
return load_contract(self.contract_path)
|
|
361
|
+
|
|
362
|
+
def init_contract(
|
|
363
|
+
self,
|
|
364
|
+
mode: str = "implement",
|
|
365
|
+
allowed_scope: list[str] | None = None,
|
|
366
|
+
acceptance_criteria: list[str] | None = None,
|
|
367
|
+
effort_profile: str = "balanced",
|
|
368
|
+
) -> dict[str, Any]:
|
|
369
|
+
"""Initializes or overwrites contract state."""
|
|
370
|
+
contract = load_contract(self.contract_path)
|
|
371
|
+
contract["mode"] = mode
|
|
372
|
+
contract["effort_profile"] = effort_profile
|
|
373
|
+
contract["allowed_write_scope"] = allowed_scope or []
|
|
374
|
+
contract["acceptance_criteria"] = acceptance_criteria or []
|
|
375
|
+
contract["last_verdict"] = "PENDING"
|
|
376
|
+
save_contract(contract, self.contract_path)
|
|
377
|
+
return contract
|
|
378
|
+
|
|
379
|
+
def generate_symbol_graph(self) -> dict[str, dict[str, Any]]:
|
|
380
|
+
"""Re-indexes workspace AST symbol graph and stores to disk."""
|
|
381
|
+
return build_symbol_graph(self.workspace_dir, self.symbol_graph_path)
|
|
382
|
+
|
|
383
|
+
def verify(self, tier: int | None = None, custom_cmd: str = "") -> dict[str, Any]:
|
|
384
|
+
"""Executes verification hierarchy."""
|
|
385
|
+
return run_verification(tier=tier, custom_cmd=custom_cmd, workspace_dir=self.workspace_dir)
|
|
386
|
+
|
|
387
|
+
def safe_patch(self, target_file: str, search_text: str, replacement_text: str) -> str:
|
|
388
|
+
"""
|
|
389
|
+
Applies surgical search-and-replace edit with Invariant 7 (Zero Elision)
|
|
390
|
+
and Invariant 2 (Scope Confinement) validation.
|
|
391
|
+
"""
|
|
392
|
+
# Invariant 7: Elision guard
|
|
393
|
+
enforce_elision_guard(replacement_text)
|
|
394
|
+
|
|
395
|
+
target_path = (self.workspace_dir / target_file).resolve()
|
|
396
|
+
norm_target = str(target_path.as_posix())
|
|
397
|
+
|
|
398
|
+
# Invariant 2: Scope Confinement
|
|
399
|
+
contract = self.get_contract()
|
|
400
|
+
allowed_scope = [str(Path(p).as_posix()) for p in contract.get("allowed_write_scope", [])]
|
|
401
|
+
if allowed_scope:
|
|
402
|
+
if not any(norm_target.endswith(s) or s in norm_target for s in allowed_scope):
|
|
403
|
+
raise PermissionError(
|
|
404
|
+
f"Invariant 2 Violation (Out of Scope): '{target_file}' is outside allowed_write_scope {allowed_scope}."
|
|
405
|
+
)
|
|
406
|
+
|
|
407
|
+
if not target_path.exists():
|
|
408
|
+
raise FileNotFoundError(f"Target file '{target_file}' does not exist.")
|
|
409
|
+
|
|
410
|
+
content = target_path.read_text(encoding="utf-8")
|
|
411
|
+
if search_text not in content:
|
|
412
|
+
raise ValueError(f"Search text not found in '{target_file}'.")
|
|
413
|
+
|
|
414
|
+
new_content = content.replace(search_text, replacement_text, 1)
|
|
415
|
+
target_path.write_text(new_content, encoding="utf-8")
|
|
416
|
+
|
|
417
|
+
contract["last_mutation_ts"] = time.time()
|
|
418
|
+
save_contract(contract, self.contract_path)
|
|
419
|
+
return f"Successfully patched '{target_file}'."
|