switchforge 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.
- forge_core/__init__.py +3 -0
- forge_core/__main__.py +6 -0
- forge_core/ai/__init__.py +0 -0
- forge_core/ai/prompts.py +87 -0
- forge_core/ai/provider.py +121 -0
- forge_core/ai/structured.py +68 -0
- forge_core/auth.py +72 -0
- forge_core/cli.py +209 -0
- forge_core/config.py +118 -0
- forge_core/core/__init__.py +0 -0
- forge_core/core/agent_manager.py +111 -0
- forge_core/core/coverage.py +241 -0
- forge_core/core/file_manager.py +104 -0
- forge_core/models/__init__.py +0 -0
- forge_core/models/config.py +115 -0
- forge_core/models/dto.py +58 -0
- forge_core/models/project.py +72 -0
- forge_core/models/test_result.py +93 -0
- forge_core/orchestrator.py +233 -0
- forge_core/phases/__init__.py +0 -0
- forge_core/phases/analyze_project.py +149 -0
- forge_core/phases/audit_tests.py +35 -0
- forge_core/phases/compile_fix.py +79 -0
- forge_core/phases/coverage_report.py +19 -0
- forge_core/phases/detect_stack.py +66 -0
- forge_core/phases/exclusion_scan.py +74 -0
- forge_core/phases/fix_broken.py +83 -0
- forge_core/phases/generate_tests.py +218 -0
- forge_core/phases/journey_mapping.py +120 -0
- forge_core/phases/self_learn.py +93 -0
- forge_core/utils/__init__.py +0 -0
- forge_core/utils/logger.py +89 -0
- forge_core/utils/reporter.py +70 -0
- forge_core/utils/shell.py +93 -0
- forge_core/utils/tokens.py +67 -0
- switchforge-1.0.0.dist-info/METADATA +65 -0
- switchforge-1.0.0.dist-info/RECORD +39 -0
- switchforge-1.0.0.dist-info/WHEEL +4 -0
- switchforge-1.0.0.dist-info/entry_points.txt +2 -0
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
"""Rich-based structured logging with progress bars."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from rich.console import Console
|
|
6
|
+
from rich.panel import Panel
|
|
7
|
+
from rich.progress import BarColumn, Progress, SpinnerColumn, TextColumn, TimeElapsedColumn
|
|
8
|
+
from rich.table import Table
|
|
9
|
+
|
|
10
|
+
console = Console()
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def phase_start(phase: str, title: str) -> None:
|
|
14
|
+
"""Log the start of a pipeline phase."""
|
|
15
|
+
console.print(f"\n[bold cyan][{phase}][/bold cyan] {title}...")
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def phase_done(phase: str, summary: str) -> None:
|
|
19
|
+
"""Log the completion of a pipeline phase."""
|
|
20
|
+
console.print(f" [green]✓[/green] {summary}")
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def phase_skip(phase: str, reason: str) -> None:
|
|
24
|
+
"""Log a skipped phase."""
|
|
25
|
+
console.print(f" [yellow]⊘[/yellow] Skipped: {reason}")
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def phase_error(phase: str, error: str) -> None:
|
|
29
|
+
"""Log a phase error."""
|
|
30
|
+
console.print(f" [red]✗[/red] Error: {error}")
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def info(msg: str) -> None:
|
|
34
|
+
console.print(f" [dim]{msg}[/dim]")
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def warn(msg: str) -> None:
|
|
38
|
+
console.print(f" [yellow]⚠[/yellow] {msg}")
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def error(msg: str) -> None:
|
|
42
|
+
console.print(f" [red]✗[/red] {msg}")
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def success(msg: str) -> None:
|
|
46
|
+
console.print(f" [green]✓[/green] {msg}")
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def banner(title: str, subtitle: str = "") -> None:
|
|
50
|
+
"""Display the Forge Core banner."""
|
|
51
|
+
text = f"[bold blue]{title}[/bold blue]"
|
|
52
|
+
if subtitle:
|
|
53
|
+
text += f"\n[dim]{subtitle}[/dim]"
|
|
54
|
+
console.print(Panel(text, border_style="blue", padding=(1, 4)))
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def coverage_table(before: float, after: float, tests_before: int, tests_after: int) -> None:
|
|
58
|
+
"""Display a before/after coverage comparison table."""
|
|
59
|
+
table = Table(title="Coverage Results", border_style="blue")
|
|
60
|
+
table.add_column("Metric", style="cyan")
|
|
61
|
+
table.add_column("Before", style="red")
|
|
62
|
+
table.add_column("After", style="green")
|
|
63
|
+
table.add_column("Delta", style="yellow")
|
|
64
|
+
|
|
65
|
+
table.add_row(
|
|
66
|
+
"Line Coverage",
|
|
67
|
+
f"{before:.1f}%",
|
|
68
|
+
f"{after:.1f}%",
|
|
69
|
+
f"+{after - before:.1f}%",
|
|
70
|
+
)
|
|
71
|
+
table.add_row(
|
|
72
|
+
"Total Tests",
|
|
73
|
+
str(tests_before),
|
|
74
|
+
str(tests_after),
|
|
75
|
+
f"+{tests_after - tests_before}",
|
|
76
|
+
)
|
|
77
|
+
console.print(table)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def create_progress() -> Progress:
|
|
81
|
+
"""Create a Rich progress bar for phase tracking."""
|
|
82
|
+
return Progress(
|
|
83
|
+
SpinnerColumn(),
|
|
84
|
+
TextColumn("[progress.description]{task.description}"),
|
|
85
|
+
BarColumn(),
|
|
86
|
+
TextColumn("[progress.percentage]{task.percentage:>3.0f}%"),
|
|
87
|
+
TimeElapsedColumn(),
|
|
88
|
+
console=console,
|
|
89
|
+
)
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"""Upload run reports to the SaaS API."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
import httpx
|
|
8
|
+
|
|
9
|
+
from forge_core.models.config import ForgeConfig
|
|
10
|
+
from forge_core.utils import logger
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
async def upload_report(config: ForgeConfig, report: dict[str, Any]) -> bool:
|
|
14
|
+
"""Upload a run report to the SaaS dashboard.
|
|
15
|
+
|
|
16
|
+
Returns True if upload succeeded, False otherwise.
|
|
17
|
+
Reports are optional — engine works fully offline.
|
|
18
|
+
"""
|
|
19
|
+
if not config.auth_token:
|
|
20
|
+
logger.info("No auth token — skipping report upload (offline mode)")
|
|
21
|
+
return False
|
|
22
|
+
|
|
23
|
+
url = f"{config.saas_api_url}/api/v1/runs"
|
|
24
|
+
headers = {
|
|
25
|
+
"Authorization": f"Bearer {config.auth_token}",
|
|
26
|
+
"Content-Type": "application/json",
|
|
27
|
+
}
|
|
28
|
+
payload = {
|
|
29
|
+
"org_id": config.tenant.org_id,
|
|
30
|
+
"user_id": config.tenant.user_id,
|
|
31
|
+
"project_id": config.tenant.project_id,
|
|
32
|
+
"report": report,
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
try:
|
|
36
|
+
async with httpx.AsyncClient(timeout=30) as client:
|
|
37
|
+
resp = await client.post(url, json=payload, headers=headers)
|
|
38
|
+
if resp.status_code == 200:
|
|
39
|
+
data = resp.json()
|
|
40
|
+
report_url = data.get("url", "")
|
|
41
|
+
logger.success(f"Report uploaded: {report_url}")
|
|
42
|
+
return True
|
|
43
|
+
else:
|
|
44
|
+
logger.warn(f"Report upload failed ({resp.status_code}): {resp.text[:200]}")
|
|
45
|
+
return False
|
|
46
|
+
except Exception as e:
|
|
47
|
+
logger.warn(f"Report upload failed (network): {e}")
|
|
48
|
+
return False
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
async def check_license(config: ForgeConfig) -> dict[str, Any]:
|
|
52
|
+
"""Check license and plan limits with the SaaS API.
|
|
53
|
+
|
|
54
|
+
Returns plan info dict or empty dict if offline/failed.
|
|
55
|
+
"""
|
|
56
|
+
if not config.auth_token:
|
|
57
|
+
return {}
|
|
58
|
+
|
|
59
|
+
url = f"{config.saas_api_url}/api/v1/license"
|
|
60
|
+
headers = {"Authorization": f"Bearer {config.auth_token}"}
|
|
61
|
+
|
|
62
|
+
try:
|
|
63
|
+
async with httpx.AsyncClient(timeout=10) as client:
|
|
64
|
+
resp = await client.get(url, headers=headers)
|
|
65
|
+
if resp.status_code == 200:
|
|
66
|
+
return resp.json()
|
|
67
|
+
except Exception:
|
|
68
|
+
pass
|
|
69
|
+
|
|
70
|
+
return {}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
"""Subprocess wrapper for running build/test commands safely."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import subprocess
|
|
6
|
+
from dataclasses import dataclass
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
from forge_core.utils import logger
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@dataclass
|
|
13
|
+
class ShellResult:
|
|
14
|
+
"""Result of a shell command execution."""
|
|
15
|
+
|
|
16
|
+
command: str
|
|
17
|
+
returncode: int
|
|
18
|
+
stdout: str
|
|
19
|
+
stderr: str
|
|
20
|
+
duration_seconds: float = 0.0
|
|
21
|
+
|
|
22
|
+
@property
|
|
23
|
+
def success(self) -> bool:
|
|
24
|
+
return self.returncode == 0
|
|
25
|
+
|
|
26
|
+
@property
|
|
27
|
+
def output(self) -> str:
|
|
28
|
+
return self.stdout + self.stderr
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def run(
|
|
32
|
+
command: str,
|
|
33
|
+
cwd: Path | str | None = None,
|
|
34
|
+
timeout: int = 600,
|
|
35
|
+
capture: bool = True,
|
|
36
|
+
env: dict[str, str] | None = None,
|
|
37
|
+
) -> ShellResult:
|
|
38
|
+
"""Run a shell command and return structured result.
|
|
39
|
+
|
|
40
|
+
Args:
|
|
41
|
+
command: Shell command to execute.
|
|
42
|
+
cwd: Working directory.
|
|
43
|
+
timeout: Max seconds before kill (default 10 min).
|
|
44
|
+
capture: Whether to capture stdout/stderr.
|
|
45
|
+
env: Extra environment variables (merged with current env).
|
|
46
|
+
"""
|
|
47
|
+
import os
|
|
48
|
+
import time
|
|
49
|
+
|
|
50
|
+
full_env = {**os.environ, **(env or {})}
|
|
51
|
+
|
|
52
|
+
logger.info(f"$ {command}")
|
|
53
|
+
|
|
54
|
+
start = time.time()
|
|
55
|
+
try:
|
|
56
|
+
result = subprocess.run(
|
|
57
|
+
command,
|
|
58
|
+
shell=True,
|
|
59
|
+
cwd=str(cwd) if cwd else None,
|
|
60
|
+
capture_output=capture,
|
|
61
|
+
text=True,
|
|
62
|
+
timeout=timeout,
|
|
63
|
+
env=full_env,
|
|
64
|
+
)
|
|
65
|
+
duration = time.time() - start
|
|
66
|
+
|
|
67
|
+
return ShellResult(
|
|
68
|
+
command=command,
|
|
69
|
+
returncode=result.returncode,
|
|
70
|
+
stdout=result.stdout or "",
|
|
71
|
+
stderr=result.stderr or "",
|
|
72
|
+
duration_seconds=duration,
|
|
73
|
+
)
|
|
74
|
+
except subprocess.TimeoutExpired:
|
|
75
|
+
duration = time.time() - start
|
|
76
|
+
logger.warn(f"Command timed out after {timeout}s: {command}")
|
|
77
|
+
return ShellResult(
|
|
78
|
+
command=command,
|
|
79
|
+
returncode=-1,
|
|
80
|
+
stdout="",
|
|
81
|
+
stderr=f"TIMEOUT after {timeout}s",
|
|
82
|
+
duration_seconds=duration,
|
|
83
|
+
)
|
|
84
|
+
except Exception as e:
|
|
85
|
+
duration = time.time() - start
|
|
86
|
+
logger.error(f"Command failed: {e}")
|
|
87
|
+
return ShellResult(
|
|
88
|
+
command=command,
|
|
89
|
+
returncode=-1,
|
|
90
|
+
stdout="",
|
|
91
|
+
stderr=str(e),
|
|
92
|
+
duration_seconds=duration,
|
|
93
|
+
)
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"""Token counting and prompt size management using tiktoken."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import tiktoken
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def count_tokens(text: str, model: str = "gpt-4o") -> int:
|
|
9
|
+
"""Count tokens in text for a given model."""
|
|
10
|
+
try:
|
|
11
|
+
enc = tiktoken.encoding_for_model(model)
|
|
12
|
+
except KeyError:
|
|
13
|
+
enc = tiktoken.get_encoding("cl100k_base")
|
|
14
|
+
return len(enc.encode(text))
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def truncate_to_tokens(text: str, max_tokens: int, model: str = "gpt-4o") -> str:
|
|
18
|
+
"""Truncate text to fit within max_tokens."""
|
|
19
|
+
try:
|
|
20
|
+
enc = tiktoken.encoding_for_model(model)
|
|
21
|
+
except KeyError:
|
|
22
|
+
enc = tiktoken.get_encoding("cl100k_base")
|
|
23
|
+
|
|
24
|
+
tokens = enc.encode(text)
|
|
25
|
+
if len(tokens) <= max_tokens:
|
|
26
|
+
return text
|
|
27
|
+
return enc.decode(tokens[:max_tokens])
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def fits_in_context(
|
|
31
|
+
system_prompt: str,
|
|
32
|
+
user_content: str,
|
|
33
|
+
model: str = "gpt-4o",
|
|
34
|
+
max_context: int = 128_000,
|
|
35
|
+
reserve_for_response: int = 4096,
|
|
36
|
+
) -> bool:
|
|
37
|
+
"""Check if system + user content fits in the model's context window."""
|
|
38
|
+
total = count_tokens(system_prompt, model) + count_tokens(user_content, model)
|
|
39
|
+
return total <= (max_context - reserve_for_response)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def split_for_context(
|
|
43
|
+
files: dict[str, str],
|
|
44
|
+
max_tokens: int,
|
|
45
|
+
model: str = "gpt-4o",
|
|
46
|
+
) -> list[dict[str, str]]:
|
|
47
|
+
"""Split a dict of {path: content} into batches that fit in context.
|
|
48
|
+
|
|
49
|
+
Returns list of batches, each a dict of {path: content}.
|
|
50
|
+
"""
|
|
51
|
+
batches: list[dict[str, str]] = []
|
|
52
|
+
current_batch: dict[str, str] = {}
|
|
53
|
+
current_tokens = 0
|
|
54
|
+
|
|
55
|
+
for path, content in files.items():
|
|
56
|
+
file_tokens = count_tokens(f"--- {path} ---\n{content}\n", model)
|
|
57
|
+
if current_tokens + file_tokens > max_tokens and current_batch:
|
|
58
|
+
batches.append(current_batch)
|
|
59
|
+
current_batch = {}
|
|
60
|
+
current_tokens = 0
|
|
61
|
+
current_batch[path] = content
|
|
62
|
+
current_tokens += file_tokens
|
|
63
|
+
|
|
64
|
+
if current_batch:
|
|
65
|
+
batches.append(current_batch)
|
|
66
|
+
|
|
67
|
+
return batches
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: switchforge
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: AI-powered backend test generation engine
|
|
5
|
+
Project-URL: Homepage, https://theswitchcompany.online/products/forge/core
|
|
6
|
+
Project-URL: Repository, https://github.com/switchcompany/forge-core
|
|
7
|
+
Project-URL: Documentation, https://theswitchcompany.online/docs/forge-core
|
|
8
|
+
Author-email: TheSwitchCompany <hello@theswitchcompany.online>
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
Keywords: ai,backend,code-generation,testing,unit-tests
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Topic :: Software Development :: Testing
|
|
19
|
+
Requires-Python: >=3.10
|
|
20
|
+
Requires-Dist: httpx>=0.27.0
|
|
21
|
+
Requires-Dist: instructor>=1.3.0
|
|
22
|
+
Requires-Dist: litellm>=1.40.0
|
|
23
|
+
Requires-Dist: pydantic>=2.7.0
|
|
24
|
+
Requires-Dist: pyyaml>=6.0
|
|
25
|
+
Requires-Dist: rich>=13.7.0
|
|
26
|
+
Requires-Dist: tiktoken>=0.7.0
|
|
27
|
+
Requires-Dist: typer>=0.12.0
|
|
28
|
+
Provides-Extra: dev
|
|
29
|
+
Requires-Dist: pyinstaller>=6.0; extra == 'dev'
|
|
30
|
+
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
|
|
31
|
+
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
32
|
+
Requires-Dist: ruff>=0.5.0; extra == 'dev'
|
|
33
|
+
Description-Content-Type: text/markdown
|
|
34
|
+
|
|
35
|
+
# Switchforge (Forge Core CLI)
|
|
36
|
+
|
|
37
|
+
AI-powered backend test generation engine by [TheSwitchCompany](https://theswitchcompany.online).
|
|
38
|
+
|
|
39
|
+
## Install
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
pip install switchforge
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Quick Start
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
switchforge login --token YOUR_API_TOKEN
|
|
49
|
+
switchforge init
|
|
50
|
+
switchforge run . --target 90
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### Windows Users
|
|
54
|
+
|
|
55
|
+
If `switchforge` is not recognized, use `python -m forge_core`:
|
|
56
|
+
|
|
57
|
+
```powershell
|
|
58
|
+
python -m forge_core login --token YOUR_API_TOKEN
|
|
59
|
+
python -m forge_core init
|
|
60
|
+
python -m forge_core run . --target 90
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Documentation
|
|
64
|
+
|
|
65
|
+
[theswitchcompany.online/docs/forge-core](https://theswitchcompany.online/docs/forge-core)
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
forge_core/__init__.py,sha256=M73aKzgrfrqVz1KEj2PCvF2he8e-pPA-CisRqUiqrTc,87
|
|
2
|
+
forge_core/__main__.py,sha256=Bgjh1sswksrd2aWTaOCPlGUGKh2M49VQ_QEB28ysRfw,116
|
|
3
|
+
forge_core/auth.py,sha256=HarMTW4dwSr-7MnJ2Fa-wYPaY2VlXMP_7Q_G6LW3syA,2391
|
|
4
|
+
forge_core/cli.py,sha256=Rqx52EKLpqaN2t4PRa7x-1-Idm9-aq7OU4nSu3-Dcxc,6405
|
|
5
|
+
forge_core/config.py,sha256=SjnHrXiuPoF-2Zl4lqpdym-6jC-53iRzUEY3GE7LyoQ,3637
|
|
6
|
+
forge_core/orchestrator.py,sha256=SlXuzoAXzllxu9BM9cWfk3HglIpAe2bLXG7M-dOXSTI,9048
|
|
7
|
+
forge_core/ai/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
8
|
+
forge_core/ai/prompts.py,sha256=1_MCoN_xDlULDEz_7uUasxaYbRSTb1pi2alk469KNQw,2733
|
|
9
|
+
forge_core/ai/provider.py,sha256=XQSCFdF9Md5p6r69vzyI7hCY4BtlfXKKf3wIPDhPoIM,3705
|
|
10
|
+
forge_core/ai/structured.py,sha256=EaS1Kig4XTofSWjQrm52HZRUzWtKbrbr8_npGk4GKOQ,1930
|
|
11
|
+
forge_core/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
12
|
+
forge_core/core/agent_manager.py,sha256=gMk8NqgYfSBk1b2-ok_nsdr1Rznlgh_pUXUJwCHGz_A,3718
|
|
13
|
+
forge_core/core/coverage.py,sha256=zmQ4x-QSEQVEpaiMFMoWWs4iuZaEwxSxPcxrdj2WCPw,8488
|
|
14
|
+
forge_core/core/file_manager.py,sha256=2JUpLYkgonkCa1pYtI0ZASxtEZ0tnQxpMN8eQuqpAC8,3820
|
|
15
|
+
forge_core/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
16
|
+
forge_core/models/config.py,sha256=JZ4oGzkHfdB91XaGe_fb0DQhx2iU3Y5gIcWkXDLTtzE,2832
|
|
17
|
+
forge_core/models/dto.py,sha256=ooVsfeNtsxsfyjl8pg6xShChE9oDvp0rzc1FNXyLEuo,1808
|
|
18
|
+
forge_core/models/project.py,sha256=w1TkrqHkaM_XGtlQVcu2A0WDRna9dod3QPohAPgIAr0,1895
|
|
19
|
+
forge_core/models/test_result.py,sha256=YOYW9iKIqFz1HQWa084KDOJcwsipvl4MXoRsHrsagU4,2381
|
|
20
|
+
forge_core/phases/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
21
|
+
forge_core/phases/analyze_project.py,sha256=GAVWGdpHsrh4RViZ67sSaQ7N2-zCwgIssTVRg-2EwUU,5412
|
|
22
|
+
forge_core/phases/audit_tests.py,sha256=zzWV7x9Q3S1iZ6szju94BhZCnZXAWiUASowYZYnPbaQ,1082
|
|
23
|
+
forge_core/phases/compile_fix.py,sha256=DQgy-yhUybddLJhut6G5FLicrrWyD8qzTXve8E0-isQ,2499
|
|
24
|
+
forge_core/phases/coverage_report.py,sha256=KveXSwoVQb-KokDnJS1EGxNidwOmyPNWv9i75b2ZJUw,648
|
|
25
|
+
forge_core/phases/detect_stack.py,sha256=vbJqxwCw1sT7pryRpP0iKd9bpPH8pQcU-2rLceTPa8E,2128
|
|
26
|
+
forge_core/phases/exclusion_scan.py,sha256=Z3vlwbaXpmlsWKJ9FS4d_d-WcuPM5eaAE05eplCQJSc,2636
|
|
27
|
+
forge_core/phases/fix_broken.py,sha256=NcovciAHgRnkV9RLcO7V2uS1CPK43liTlJkKJbFywlQ,2676
|
|
28
|
+
forge_core/phases/generate_tests.py,sha256=lWA0rozpU6nbeMV-ag2coEO-Nu7LPJDmPK75CGcYww8,7782
|
|
29
|
+
forge_core/phases/journey_mapping.py,sha256=BmBA3yYRaWUNgOsqdMvQtZ41W_Te0FKTgX9G5TebqcU,4299
|
|
30
|
+
forge_core/phases/self_learn.py,sha256=HK_CagBIRjn9eeWpr5bUCvfN29HRD5E7CjblUyXVXZk,3317
|
|
31
|
+
forge_core/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
32
|
+
forge_core/utils/logger.py,sha256=b_PaZgxdERw0lAaWLFsnrnfffrCSUhn4UpESj97crAs,2533
|
|
33
|
+
forge_core/utils/reporter.py,sha256=yhzaMoByj9tM0RAHefcv8sPcEWbTESiev98usm9zgzk,2145
|
|
34
|
+
forge_core/utils/shell.py,sha256=mRn2tNMRtdOxXkst6DWasVBd0pRVGJmaqKukU-QHd_c,2367
|
|
35
|
+
forge_core/utils/tokens.py,sha256=YQZ4AOkuOwUYghFZicGC6isnLdyro-3j3tDNEkI3lM0,1997
|
|
36
|
+
switchforge-1.0.0.dist-info/METADATA,sha256=WvYw-iz4eBiQ_Kh4ZlXQgdb1bK18fjTOP_Rf4NXpQSE,1995
|
|
37
|
+
switchforge-1.0.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
38
|
+
switchforge-1.0.0.dist-info/entry_points.txt,sha256=PwgdQo8NrcBuvyW3DlkfyF2Wa0XXNkHyir20DsD86dY,51
|
|
39
|
+
switchforge-1.0.0.dist-info/RECORD,,
|