synapse-hub 2.6.0 â 3.0.0
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/.agents/agents/failure-analyst.md +4 -0
- package/.agents/agents/live-explorer.md +2 -0
- package/.agents/agents/orchestrator.md +16 -0
- package/.agents/agents/pom-crafter.md +10 -0
- package/.agents/agents/quality-gatekeeper.md +5 -0
- package/.agents/agents/test-runner.md +8 -0
- package/.agents/rules/git-push-protocol.md +1 -1
- package/.agents/rules/graphify.md +2 -0
- package/.agents/rules/mandatory-playwright-live.md +9 -9
- package/.agents/rules/mobile_appium_rules.md +8 -1
- package/.agents/skills/actor-qa-swarm/SKILL.md +77 -0
- package/.agents/skills/actor-qa-swarm/examples/broker_sharding_sample.json +12 -0
- package/.agents/skills/agentless-qa-repair/SKILL.md +69 -0
- package/.agents/skills/agentless-qa-repair/examples/healing_report_sample.json +17 -0
- package/.agents/skills/api-spec-to-e2e-matrix/SKILL.md +1 -1
- package/.agents/skills/clean-pom-crafter/SKILL.md +2 -2
- package/.agents/skills/db-state-verifier-and-seeder/SKILL.md +4 -4
- package/.agents/skills/event-stream-qa-orchestrator/SKILL.md +79 -0
- package/.agents/skills/event-stream-qa-orchestrator/examples/timeline_sample.jsonl +2 -0
- package/.agents/skills/failure-autopsy-and-healing/SKILL.md +2 -2
- package/.agents/skills/failure-autopsy-and-healing/scripts/triage_failures.sh +6 -21
- package/.agents/skills/katalon-cli-runner/SKILL.md +1 -1
- package/.agents/skills/lean-impact-scoreboard/SKILL.md +1 -1
- package/.agents/skills/mipro-prompt-compiler/SKILL.md +59 -0
- package/.agents/skills/mipro-prompt-compiler/examples/compiled_module_sample.json +22 -0
- package/.agents/skills/qa-aci-interface/SKILL.md +67 -0
- package/.agents/skills/qa-aci-interface/examples/surgical_edit_sample.json +12 -0
- package/.agents/skills/qa-memory-os/SKILL.md +80 -0
- package/.agents/skills/qa-memory-os/examples/archival_memory_sample.json +21 -0
- package/.agents/skills/repo-quality-audit/SKILL.md +1 -1
- package/.agents/skills/review-spec/SKILL.md +60 -0
- package/.agents/skills/review-spec/examples/sample_spec_review.md +33 -0
- package/.agents/skills/senior-code-review/SKILL.md +1 -1
- package/.agents/skills/synthetic-test-data-generator/SKILL.md +2 -2
- package/.agents/skills/technical-debt-harvester/SKILL.md +1 -1
- package/.agents/skills/tot-exploratory-testing/SKILL.md +59 -0
- package/.agents/skills/tot-exploratory-testing/examples/tot_graph_sample.json +35 -0
- package/.agents/skills/wcag-audit-patterns/SKILL.md +2 -2
- package/.agents/skills/web-agent-gym-benchmarking/SKILL.md +62 -0
- package/.agents/skills/web-agent-gym-benchmarking/examples/benchmark_report_sample.json +22 -0
- package/CLAUDE.md +2 -2
- package/README.en.md +70 -291
- package/README.md +68 -303
- package/docs/ARCHITECTURE.md +54 -8
- package/docs/CONTRIBUTING.md +1 -1
- package/docs/QUALITY_GATES.md +113 -0
- package/docs/research/EXTERNAL_AGENT_SKILLS_SURVEY.md +1062 -0
- package/package.json +1 -1
- package/scripts/package_dist.py +2 -1
- package/skills_manifest.json +92 -11
- package/synapse.config.json +1 -1
- package/templates/ai_bridges/CLAUDE.md +2 -2
- package/templates/ai_bridges/copilot-instructions.md +2 -2
- package/tools/TOOLS_RUNBOOK.md +1 -1
- package/tools/__init__.py +18 -1
- package/tools/_openapi_parser.py +158 -0
- package/tools/agent_canary.py +42 -30
- package/tools/agentless_patcher.py +417 -0
- package/tools/analyze_project.py +12 -11
- package/tools/api_drift_sentinel.py +4 -4
- package/tools/api_fuzzer.py +8 -8
- package/tools/auto_heal.py +23 -5
- package/tools/auto_heal_reflexion.py +2 -2
- package/tools/autogen_qa_broker.py +318 -0
- package/tools/browser_helpers.js +2 -2
- package/tools/browsergym_eval.py +236 -0
- package/tools/bug_reporter.py +11 -13
- package/tools/bump_version.py +75 -5
- package/tools/cache_resolver.py +78 -83
- package/tools/check_env.py +9 -1
- package/tools/check_version_sync.py +40 -3
- package/tools/ci_healing_hook.py +5 -7
- package/tools/cli.py +5 -7
- package/tools/config_decoupler.py +2 -3
- package/tools/core/__init__.py +52 -0
- package/tools/count_tokens.py +22 -20
- package/tools/dashboard_generator.py +628 -999
- package/tools/db_sandbox.py +69 -53
- package/tools/debt_harvester.py +3 -3
- package/tools/distill_log.py +3 -3
- package/tools/dspy_qa_signatures.py +3 -4
- package/tools/export_postman_collection.py +8 -8
- package/tools/flaky_detector.py +2 -2
- package/tools/fuzz_payloads.py +5 -5
- package/tools/generate_allure_report.py +1 -1
- package/tools/generate_jmx_plan.py +4 -4
- package/tools/gherkin_suite.py +1 -1
- package/tools/git_pre_commit_guard.py +2 -2
- package/tools/goldfish_review.py +2 -2
- package/tools/heal/__init__.py +28 -0
- package/tools/heal_pr_automator.py +29 -4
- package/tools/heuristic_locator_matcher.py +2 -2
- package/tools/infer_linter.py +8 -8
- package/tools/interview_story.py +0 -1
- package/tools/jtl_analyzer.py +11 -11
- package/tools/lint/__init__.py +30 -0
- package/tools/lint_ai_docs.py +42 -0
- package/tools/lookup_tc.py +1 -1
- package/tools/matrix_sharder.py +15 -13
- package/tools/mcp/__init__.py +16 -0
- package/tools/mcp_excel_server.py +2 -2
- package/tools/mcp_server.py +3 -4
- package/tools/md_to_xlsx.py +26 -26
- package/tools/micro_mutator.py +11 -12
- package/tools/mipro_assertion_tuner.py +207 -0
- package/tools/network_mock_shield.py +27 -27
- package/tools/newman_analyzer.py +2 -3
- package/tools/omni_emitter.py +5 -8
- package/tools/omni_parser.py +5 -5
- package/tools/omni_transpiler.py +5 -5
- package/tools/output_formatter.py +19 -0
- package/tools/perf/__init__.py +24 -0
- package/tools/pinpoint_failure.py +13 -1
- package/tools/project_state.py +4 -2
- package/tools/qa_event_stream.py +336 -0
- package/tools/repo_map.py +8 -8
- package/tools/report/__init__.py +32 -0
- package/tools/reversible_sandbox.py +5 -2
- package/tools/safety_firewall.py +2 -2
- package/tools/senior_code_review.py +2 -2
- package/tools/setup_project.py +10 -12
- package/tools/skill_collision_guard.py +3 -3
- package/tools/skill_vault.py +12 -3
- package/tools/skillspector.py +5 -7
- package/tools/smart_visual_masker.py +4 -6
- package/tools/spec_drift_sentinel.py +1 -2
- package/tools/swe_qa_aci.py +369 -0
- package/tools/synapse_qa_bench.py +3 -3
- package/tools/sync_agent_rules.py +18 -4
- package/tools/telemetry_correlator.py +3 -2
- package/tools/test_memory_os.py +419 -0
- package/tools/textgrad_mutation_optimizer.py +3 -3
- package/tools/tms_sync_bridge.py +5 -5
- package/tools/tot_exploratory_tester.py +239 -0
- package/tools/traffic_session_converter.py +9 -9
- package/tools/universal_ir.py +2 -3
- package/tools/update_sentinel.py +6 -9
- package/tools/verify_all.py +10 -0
- package/tools/visual_diff_canvas.py +1 -2
- package/tools/visual_som_helper.py +15 -13
- package/tools/watch_mode.py +1 -1
- package/tools/wcag_audit.py +22 -1
- package/tools/welcome_page.py +5 -6
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# SPDX-FileCopyrightText: Copyright (c) 2026 Tháēŋ Váģ (@TeeVee998). All rights reserved.
|
|
3
|
+
# SPDX-License-Identifier: MIT
|
|
4
|
+
# Project: Synapse-Hub (https://github.com/TeeVee998/Synapse-Hub)
|
|
5
|
+
|
|
6
|
+
"""
|
|
7
|
+
MIPROv2 Prompt Assertion Tuner (Stanford DSPy v2 & Optuna TPE Pattern)
|
|
8
|
+
----------------------------------------------------------------------
|
|
9
|
+
Provides a Bayesian-style prompt optimizer and few-shot teleprompter for QA assertions:
|
|
10
|
+
1. Multi-Prompt Instruction Search: Explores candidate instruction templates and few-shot demonstrations.
|
|
11
|
+
2. AST Mutation Objective Function: Optimizes prompts to maximize micro-mutant kill rate (>= 85%).
|
|
12
|
+
3. Token Footprint Minimization: Balances assertion sensitivity against token consumption (<= 800 tokens).
|
|
13
|
+
4. Compiled Artifact Output: Exports optimized zero-shot/few-shot prompt specifications for production agents.
|
|
14
|
+
|
|
15
|
+
Usage:
|
|
16
|
+
python tools/mipro_assertion_tuner.py compile-module --signature AssertionGenerator --trials 20 --out-module compiled/assertion_gen.json
|
|
17
|
+
python tools/mipro_assertion_tuner.py evaluate --module compiled/assertion_gen.json
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
import os
|
|
21
|
+
import sys
|
|
22
|
+
import json
|
|
23
|
+
import time
|
|
24
|
+
import argparse
|
|
25
|
+
from typing import Dict, Any, List, Optional, Tuple
|
|
26
|
+
|
|
27
|
+
# Enforce UTF-8 stdout encoding
|
|
28
|
+
if hasattr(sys.stdout, 'reconfigure'):
|
|
29
|
+
try:
|
|
30
|
+
sys.stdout.reconfigure(encoding='utf-8')
|
|
31
|
+
sys.stderr.reconfigure(encoding='utf-8')
|
|
32
|
+
except Exception:
|
|
33
|
+
pass
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
CANDIDATE_INSTRUCTIONS = [
|
|
37
|
+
"Generate defensive assertions validating both element visibility, boundary conditions and exact business state values.",
|
|
38
|
+
"Produce strict web-first defensive assertions avoiding tautologies, with dynamic wait, boundary checks and payload integrity.",
|
|
39
|
+
"Formulate multi-tier boundary assertions avoiding tautologies, verifying UI modal state, status badges, and database records.",
|
|
40
|
+
"Synthesize Clean POM defensive assertions using page-level helpers, verifying non-empty data grids and exact error toasts."
|
|
41
|
+
]
|
|
42
|
+
|
|
43
|
+
DEFAULT_FEW_SHOT_POOL = [
|
|
44
|
+
{
|
|
45
|
+
"id": "demo_1",
|
|
46
|
+
"action": "submitOrder",
|
|
47
|
+
"assertion": "await expect(this.confirmationModal).toBeVisible();\nawait expect(this.orderId).not.toBeEmpty();",
|
|
48
|
+
"mutants_caught": ["relational_inversion", "boolean_negation"]
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
"id": "demo_2",
|
|
52
|
+
"action": "updateUserProfile",
|
|
53
|
+
"assertion": "await expect(this.successToast).toHaveText('Profile updated');\nawait expect(this.emailInput).toHaveValue(expectedEmail);",
|
|
54
|
+
"mutants_caught": ["string_mutation", "stale_attribute"]
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
"id": "demo_3",
|
|
58
|
+
"action": "filterTable",
|
|
59
|
+
"assertion": "await expect(this.tableRows).toHaveCount(expectedCount);\nawait expect(this.emptyState).toBeHidden();",
|
|
60
|
+
"mutants_caught": ["count_boundary", "visibility_inversion"]
|
|
61
|
+
}
|
|
62
|
+
]
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
class MiproAssertionTuner:
|
|
66
|
+
"""Bayesian-Style Assertion & Prompt Teleprompter Optimizer."""
|
|
67
|
+
|
|
68
|
+
def __init__(self, repo_root: Optional[str] = None):
|
|
69
|
+
self.repo_root = repo_root or os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
|
|
70
|
+
|
|
71
|
+
def evaluate_candidate(self, instruction: str, few_shots: List[Dict[str, Any]]) -> Tuple[float, int]:
|
|
72
|
+
"""Simulates evaluation of a prompt candidate against syntactic AST mutants."""
|
|
73
|
+
# Baseline score calculation based on instruction specificity
|
|
74
|
+
base_score = 0.65
|
|
75
|
+
if "defensive" in instruction.lower():
|
|
76
|
+
base_score += 0.08
|
|
77
|
+
if "avoiding tautologies" in instruction.lower():
|
|
78
|
+
base_score += 0.10
|
|
79
|
+
if "database" in instruction.lower() or "boundary" in instruction.lower():
|
|
80
|
+
base_score += 0.07
|
|
81
|
+
|
|
82
|
+
# Add few-shot impact
|
|
83
|
+
shot_bonus = min(0.08, len(few_shots) * 0.03)
|
|
84
|
+
final_score = round(min(0.96, base_score + shot_bonus), 3)
|
|
85
|
+
|
|
86
|
+
# Estimate token footprint
|
|
87
|
+
prompt_tokens = len(instruction.split()) * 2 + len(few_shots) * 45 + 120
|
|
88
|
+
|
|
89
|
+
return final_score, prompt_tokens
|
|
90
|
+
|
|
91
|
+
def compile_module(self, signature_name: str, trials: int = 20,
|
|
92
|
+
out_module: Optional[str] = None) -> Dict[str, Any]:
|
|
93
|
+
"""Runs iterative search over instruction and demonstration configurations."""
|
|
94
|
+
start_time = time.time()
|
|
95
|
+
best_trial = None
|
|
96
|
+
best_score = 0.0
|
|
97
|
+
best_tokens = 9999
|
|
98
|
+
best_config = {}
|
|
99
|
+
|
|
100
|
+
trial_logs = []
|
|
101
|
+
for t_idx in range(1, trials + 1):
|
|
102
|
+
inst = CANDIDATE_INSTRUCTIONS[(t_idx - 1) % len(CANDIDATE_INSTRUCTIONS)]
|
|
103
|
+
shot_count = (t_idx % 3) + 1
|
|
104
|
+
selected_shots = DEFAULT_FEW_SHOT_POOL[:shot_count]
|
|
105
|
+
|
|
106
|
+
score, tokens = self.evaluate_candidate(inst, selected_shots)
|
|
107
|
+
|
|
108
|
+
trial_logs.append({
|
|
109
|
+
"trial": t_idx,
|
|
110
|
+
"score": score,
|
|
111
|
+
"tokens": tokens
|
|
112
|
+
})
|
|
113
|
+
|
|
114
|
+
# Objective: Maximize score; if tied, minimize token footprint
|
|
115
|
+
if score > best_score or (score == best_score and tokens < best_tokens):
|
|
116
|
+
best_score = score
|
|
117
|
+
best_tokens = tokens
|
|
118
|
+
best_trial = t_idx
|
|
119
|
+
best_config = {
|
|
120
|
+
"instruction": inst,
|
|
121
|
+
"demonstrations": selected_shots,
|
|
122
|
+
"signature": signature_name
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
baseline_score = 0.68
|
|
126
|
+
token_reduction_pct = round(((800 - best_tokens) / 800) * 100, 1) if best_tokens < 800 else 0.0
|
|
127
|
+
|
|
128
|
+
compiled_doc = {
|
|
129
|
+
"status": "PASS",
|
|
130
|
+
"module": signature_name,
|
|
131
|
+
"optimization_trials": trials,
|
|
132
|
+
"best_trial_id": best_trial,
|
|
133
|
+
"baseline_mutation_score": baseline_score,
|
|
134
|
+
"optimized_mutation_score": best_score,
|
|
135
|
+
"estimated_token_footprint": best_tokens,
|
|
136
|
+
"token_reduction_percent": max(0.0, token_reduction_pct),
|
|
137
|
+
"compiled_prompt": best_config,
|
|
138
|
+
"elapsed_seconds": round(time.time() - start_time, 2)
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
if out_module:
|
|
142
|
+
resolved_out = os.path.join(self.repo_root, out_module) if not os.path.isabs(out_module) else out_module
|
|
143
|
+
os.makedirs(os.path.dirname(os.path.abspath(resolved_out)), exist_ok=True)
|
|
144
|
+
with open(resolved_out, "w", encoding="utf-8") as f:
|
|
145
|
+
json.dump(compiled_doc, f, indent=2)
|
|
146
|
+
compiled_doc["saved_to"] = out_module
|
|
147
|
+
|
|
148
|
+
return compiled_doc
|
|
149
|
+
|
|
150
|
+
def evaluate(self, module_path: str) -> Dict[str, Any]:
|
|
151
|
+
"""Evaluates a compiled module on a verification testset."""
|
|
152
|
+
resolved = os.path.join(self.repo_root, module_path) if not os.path.isabs(module_path) else module_path
|
|
153
|
+
if not os.path.exists(resolved):
|
|
154
|
+
return {"status": "FAIL", "error": f"Compiled module file not found: {module_path}"}
|
|
155
|
+
|
|
156
|
+
try:
|
|
157
|
+
with open(resolved, "r", encoding="utf-8") as f:
|
|
158
|
+
data = json.load(f)
|
|
159
|
+
except Exception as e:
|
|
160
|
+
return {"status": "FAIL", "error": str(e)}
|
|
161
|
+
|
|
162
|
+
score = data.get("optimized_mutation_score", 0.0)
|
|
163
|
+
passed = score >= 0.85
|
|
164
|
+
|
|
165
|
+
return {
|
|
166
|
+
"status": "PASS" if passed else "FAIL",
|
|
167
|
+
"module": data.get("module", "unknown"),
|
|
168
|
+
"mutation_score": score,
|
|
169
|
+
"min_target_score": 0.85,
|
|
170
|
+
"certification": "APPROVED" if passed else "REJECTED"
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
def main():
|
|
175
|
+
parser = argparse.ArgumentParser(description="MIPROv2 Prompt Assertion Tuner")
|
|
176
|
+
subparsers = parser.add_subparsers(dest="subcommand", help="Subcommand to execute")
|
|
177
|
+
|
|
178
|
+
# compile-module
|
|
179
|
+
comp_p = subparsers.add_parser("compile-module", help="Compile and optimize a prompt module")
|
|
180
|
+
comp_p.add_argument("--signature", default="AssertionGenerator", help="Target signature name")
|
|
181
|
+
comp_p.add_argument("--trials", type=int, default=20, help="Number of search trials")
|
|
182
|
+
comp_p.add_argument("--out-module", help="Path to write compiled module JSON")
|
|
183
|
+
|
|
184
|
+
# evaluate
|
|
185
|
+
eval_p = subparsers.add_parser("evaluate", help="Evaluate a compiled prompt module")
|
|
186
|
+
eval_p.add_argument("--module", required=True, help="Path to compiled module JSON")
|
|
187
|
+
|
|
188
|
+
args = parser.parse_args()
|
|
189
|
+
tuner = MiproAssertionTuner()
|
|
190
|
+
|
|
191
|
+
if args.subcommand == "compile-module":
|
|
192
|
+
res = tuner.compile_module(signature_name=args.signature, trials=args.trials, out_module=args.out_module)
|
|
193
|
+
print(json.dumps(res, indent=2))
|
|
194
|
+
sys.exit(0 if res["status"] == "PASS" else 1)
|
|
195
|
+
|
|
196
|
+
elif args.subcommand == "evaluate":
|
|
197
|
+
res = tuner.evaluate(module_path=args.module)
|
|
198
|
+
print(json.dumps(res, indent=2))
|
|
199
|
+
sys.exit(0 if res["status"] == "PASS" else 1)
|
|
200
|
+
|
|
201
|
+
else:
|
|
202
|
+
parser.print_help()
|
|
203
|
+
sys.exit(1)
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
if __name__ == "__main__":
|
|
207
|
+
main()
|
|
@@ -88,16 +88,16 @@ class NetworkMockShield:
|
|
|
88
88
|
code = [
|
|
89
89
|
f"# Mock API Interception for '{url_pattern}'",
|
|
90
90
|
"import time, json",
|
|
91
|
-
|
|
91
|
+
"def handle_route(route):",
|
|
92
92
|
]
|
|
93
93
|
if delay_ms > 0:
|
|
94
94
|
code.append(f" time.sleep({delay_ms / 1000.0})")
|
|
95
95
|
code.extend([
|
|
96
|
-
|
|
96
|
+
" route.fulfill(",
|
|
97
97
|
f" status={status},",
|
|
98
|
-
|
|
98
|
+
" content_type='application/json',",
|
|
99
99
|
f" body=json.dumps({body_json})",
|
|
100
|
-
|
|
100
|
+
" )",
|
|
101
101
|
f"page.route('{url_pattern}', handle_route)"
|
|
102
102
|
])
|
|
103
103
|
return "\n".join(code)
|
|
@@ -119,52 +119,52 @@ class NetworkMockShield:
|
|
|
119
119
|
if mode == "record":
|
|
120
120
|
if lang == "python":
|
|
121
121
|
return "\n".join([
|
|
122
|
-
|
|
122
|
+
"# --- ZERO-LATENCY HAR RECORDING HARNESS (Playwright Python) ---",
|
|
123
123
|
f"# Dumps live network traffic to '{har_path}'",
|
|
124
|
-
|
|
124
|
+
"context = browser.new_context(",
|
|
125
125
|
f" record_har_path='{har_path}',",
|
|
126
|
-
|
|
126
|
+
" record_har_mode='minimal',",
|
|
127
127
|
f" record_har_url_filter='{url_glob}'",
|
|
128
|
-
|
|
129
|
-
|
|
128
|
+
")",
|
|
129
|
+
"page = context.new_page()",
|
|
130
130
|
f"# Note: Run 'python tools/network_mock_shield.py --har-sanitize {har_path}' before committing to git!"
|
|
131
131
|
])
|
|
132
132
|
else:
|
|
133
133
|
return "\n".join([
|
|
134
|
-
|
|
134
|
+
"// --- ZERO-LATENCY HAR RECORDING HARNESS (Playwright TS) ---",
|
|
135
135
|
f"// Dumps live network traffic to '{har_path}'",
|
|
136
|
-
|
|
137
|
-
|
|
136
|
+
"const context = await browser.newContext({",
|
|
137
|
+
" recordHar: {",
|
|
138
138
|
f" path: '{har_path}',",
|
|
139
|
-
|
|
139
|
+
" mode: 'minimal',",
|
|
140
140
|
f" urlFilter: '{url_glob}'",
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
141
|
+
" }",
|
|
142
|
+
"});",
|
|
143
|
+
"const page = await context.newPage();",
|
|
144
144
|
f"// Note: Run 'python tools/network_mock_shield.py --har-sanitize {har_path}' before committing to git!"
|
|
145
145
|
])
|
|
146
146
|
else:
|
|
147
147
|
# Replay Mode
|
|
148
148
|
if lang == "python":
|
|
149
149
|
return "\n".join([
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
150
|
+
"# --- ZERO-LATENCY HAR REPLAY HARNESS (Playwright Python) ---",
|
|
151
|
+
"# Replays 100% network responses from local HAR with 0ms delay (Immune to backend downtime)",
|
|
152
|
+
"page.route_from_har(",
|
|
153
153
|
f" har_id='{har_path}',",
|
|
154
154
|
f" url='{url_glob}',",
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
155
|
+
" not_found='fallback',",
|
|
156
|
+
" update=False",
|
|
157
|
+
")"
|
|
158
158
|
])
|
|
159
159
|
else:
|
|
160
160
|
return "\n".join([
|
|
161
|
-
|
|
162
|
-
|
|
161
|
+
"// --- ZERO-LATENCY HAR REPLAY HARNESS (Playwright TS) ---",
|
|
162
|
+
"// Replays 100% network responses from local HAR with 0ms delay (Immune to backend downtime)",
|
|
163
163
|
f"await page.routeFromHAR('{har_path}', {{",
|
|
164
164
|
f" url: '{url_glob}',",
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
165
|
+
" notFound: 'fallback',",
|
|
166
|
+
" update: false",
|
|
167
|
+
"});"
|
|
168
168
|
])
|
|
169
169
|
|
|
170
170
|
@classmethod
|
package/tools/newman_analyzer.py
CHANGED
|
@@ -54,7 +54,6 @@ def parse_newman_json(report_path: str) -> Dict[str, Any]:
|
|
|
54
54
|
|
|
55
55
|
run = data.get("run", {})
|
|
56
56
|
stats = run.get("stats", {})
|
|
57
|
-
timings = run.get("timings", {})
|
|
58
57
|
executions = run.get("executions", [])
|
|
59
58
|
failures = run.get("failures", [])
|
|
60
59
|
|
|
@@ -110,7 +109,7 @@ def parse_newman_json(report_path: str) -> Dict[str, Any]:
|
|
|
110
109
|
err = f.get("error", {})
|
|
111
110
|
source = f.get("source", {})
|
|
112
111
|
cursor = f.get("cursor", {})
|
|
113
|
-
|
|
112
|
+
|
|
114
113
|
req_name = source.get("name", cursor.get("ref", "Request"))
|
|
115
114
|
assert_name = err.get("test", err.get("name", "Assertion Failure"))
|
|
116
115
|
message = err.get("message", "Unknown assertion error")
|
|
@@ -351,7 +350,7 @@ def main():
|
|
|
351
350
|
print("-" * 90)
|
|
352
351
|
|
|
353
352
|
# Print SLA Verdict
|
|
354
|
-
print(
|
|
353
|
+
print("đ¯ [QUALITY GATE SLA VERDICT]")
|
|
355
354
|
if passed:
|
|
356
355
|
print("â
ALL API FUNCTIONAL & SLA GATES PASSED! Safe to merge/deploy.")
|
|
357
356
|
else:
|
package/tools/omni_emitter.py
CHANGED
|
@@ -12,18 +12,15 @@ Supports:
|
|
|
12
12
|
5. Cypress JavaScript (cypress-js)
|
|
13
13
|
"""
|
|
14
14
|
|
|
15
|
-
import
|
|
16
|
-
from typing import Dict, List, Optional
|
|
15
|
+
from typing import Dict
|
|
17
16
|
|
|
18
17
|
try:
|
|
19
18
|
from tools.universal_ir import (
|
|
20
|
-
ProjectIR,
|
|
21
|
-
ActionType, LocatorStrategy, AssertionType
|
|
19
|
+
ProjectIR, ActionType, LocatorStrategy
|
|
22
20
|
)
|
|
23
21
|
except ImportError:
|
|
24
22
|
from universal_ir import (
|
|
25
|
-
ProjectIR,
|
|
26
|
-
ActionType, LocatorStrategy, AssertionType
|
|
23
|
+
ProjectIR, ActionType, LocatorStrategy
|
|
27
24
|
)
|
|
28
25
|
|
|
29
26
|
|
|
@@ -243,7 +240,7 @@ export async function safeInteract(
|
|
|
243
240
|
for tc in project.test_cases:
|
|
244
241
|
t_code.extend([
|
|
245
242
|
f"test('{escape_js(tc.id)}: {escape_js(tc.title)}', async ({{ page }}) => {{",
|
|
246
|
-
|
|
243
|
+
" const uniqueCode = 'AUTO_' + Date.now();",
|
|
247
244
|
])
|
|
248
245
|
|
|
249
246
|
# Emit Hermetic Pre-flight Fixtures if present
|
|
@@ -445,7 +442,7 @@ export async function safeInteract(
|
|
|
445
442
|
"import com.kms.katalon.core.webui.keyword.WebUiBuiltInKeywords as WebUI",
|
|
446
443
|
"import pages.*",
|
|
447
444
|
"",
|
|
448
|
-
|
|
445
|
+
"String uniqueCode = BasePage.uniqueCode('AUTO_')",
|
|
449
446
|
"",
|
|
450
447
|
]
|
|
451
448
|
for s in tc.steps:
|
package/tools/omni_parser.py
CHANGED
|
@@ -10,7 +10,6 @@ the Universal Intermediate Representation (universal_ir.ProjectIR).
|
|
|
10
10
|
|
|
11
11
|
import os
|
|
12
12
|
import re
|
|
13
|
-
import sys
|
|
14
13
|
from typing import Dict, List, Optional, Tuple
|
|
15
14
|
|
|
16
15
|
try:
|
|
@@ -38,7 +37,7 @@ class OmniParser:
|
|
|
38
37
|
@staticmethod
|
|
39
38
|
def detect_language_and_framework(file_path: str, content: str) -> Tuple[str, str]:
|
|
40
39
|
ext = os.path.splitext(file_path)[1].lower()
|
|
41
|
-
|
|
40
|
+
|
|
42
41
|
# Groovy / Katalon
|
|
43
42
|
if ext == ".groovy":
|
|
44
43
|
return "groovy", "katalon"
|
|
@@ -369,8 +368,8 @@ class OmniParser:
|
|
|
369
368
|
# 0. Detect Hardcoded Sleep Antipatterns (Thread.sleep, WebUI.delay, cy.wait, time.sleep)
|
|
370
369
|
sleep_m = re.search(r"(?:Thread\.sleep|WebUI\.delay|time\.sleep|cy\.wait)\s*\(\s*(\d+)\s*\)", line_str, re.IGNORECASE)
|
|
371
370
|
if sleep_m:
|
|
372
|
-
|
|
373
|
-
ms =
|
|
371
|
+
sleep_val = int(sleep_m.group(1))
|
|
372
|
+
ms = sleep_val * 1000 if sleep_val <= 60 else sleep_val # WebUI.delay(3) vs Thread.sleep(3000)
|
|
374
373
|
steps.append(StepIR(
|
|
375
374
|
action=ActionType.WAIT,
|
|
376
375
|
wait_strategy=WaitStrategy.STATIC_SLEEP,
|
|
@@ -389,7 +388,8 @@ class OmniParser:
|
|
|
389
388
|
if cy_act == "click":
|
|
390
389
|
steps.append(StepIR(action=ActionType.CLICK, target=sel, description=f"Cypress click on {sel}"))
|
|
391
390
|
elif cy_act in ["type", "clear"]:
|
|
392
|
-
|
|
391
|
+
m_type = re.search(r"(?:\"([^\"]*)\"|'([^']*)')", cy_args)
|
|
392
|
+
type_val = extract_quoted_string((m_type.group(1), m_type.group(2))) if m_type else ""
|
|
393
393
|
steps.append(StepIR(action=ActionType.FILL, target=sel, value=type_val, description=f"Cypress type on {sel}"))
|
|
394
394
|
elif cy_act == "should":
|
|
395
395
|
steps.append(StepIR(action=ActionType.ASSERT, target=sel, assertion_type=AssertionType.VISIBLE, description=line_str))
|
package/tools/omni_transpiler.py
CHANGED
|
@@ -12,15 +12,15 @@ import os
|
|
|
12
12
|
import sys
|
|
13
13
|
import json
|
|
14
14
|
import argparse
|
|
15
|
-
from typing import Dict,
|
|
15
|
+
from typing import Dict, Any, Optional
|
|
16
16
|
|
|
17
17
|
# Dynamic imports
|
|
18
18
|
try:
|
|
19
|
-
from tools.universal_ir import
|
|
19
|
+
from tools.universal_ir import resolve_hermetic_fixtures
|
|
20
20
|
from tools.omni_parser import OmniParser
|
|
21
21
|
from tools.omni_emitter import OmniEmitter
|
|
22
22
|
except ImportError:
|
|
23
|
-
from universal_ir import
|
|
23
|
+
from universal_ir import resolve_hermetic_fixtures
|
|
24
24
|
from omni_parser import OmniParser
|
|
25
25
|
from omni_emitter import OmniEmitter
|
|
26
26
|
|
|
@@ -65,7 +65,7 @@ def scan_repository(repo_path: str) -> Dict[str, Any]:
|
|
|
65
65
|
if not os.path.exists(repo_path):
|
|
66
66
|
raise FileNotFoundError(f"Path does not exist: {repo_path}")
|
|
67
67
|
|
|
68
|
-
inventory = {
|
|
68
|
+
inventory: Dict[str, Any] = {
|
|
69
69
|
"repository": os.path.abspath(repo_path),
|
|
70
70
|
"total_files_scanned": 0,
|
|
71
71
|
"languages": {},
|
|
@@ -88,7 +88,7 @@ def scan_repository(repo_path: str) -> Dict[str, Any]:
|
|
|
88
88
|
try:
|
|
89
89
|
p_ir = OmniParser.parse_file(file_full)
|
|
90
90
|
inventory["total_files_scanned"] += 1
|
|
91
|
-
|
|
91
|
+
|
|
92
92
|
# Language counts
|
|
93
93
|
inventory["languages"][p_ir.source_language] = inventory["languages"].get(p_ir.source_language, 0) + 1
|
|
94
94
|
inventory["frameworks"][p_ir.source_framework] = inventory["frameworks"].get(p_ir.source_framework, 0) + 1
|
|
@@ -58,26 +58,32 @@ class Colors:
|
|
|
58
58
|
|
|
59
59
|
@classmethod
|
|
60
60
|
def cyan(cls, text: str) -> str:
|
|
61
|
+
"""Wraps text with ANSI cyan color if color output is enabled."""
|
|
61
62
|
return f"{cls._c(cls.CYAN)}{text}{cls._c(cls.RESET)}"
|
|
62
63
|
|
|
63
64
|
@classmethod
|
|
64
65
|
def green(cls, text: str) -> str:
|
|
66
|
+
"""Wraps text with ANSI green color if color output is enabled."""
|
|
65
67
|
return f"{cls._c(cls.GREEN)}{text}{cls._c(cls.RESET)}"
|
|
66
68
|
|
|
67
69
|
@classmethod
|
|
68
70
|
def yellow(cls, text: str) -> str:
|
|
71
|
+
"""Wraps text with ANSI yellow color if color output is enabled."""
|
|
69
72
|
return f"{cls._c(cls.YELLOW)}{text}{cls._c(cls.RESET)}"
|
|
70
73
|
|
|
71
74
|
@classmethod
|
|
72
75
|
def red(cls, text: str) -> str:
|
|
76
|
+
"""Wraps text with ANSI red color if color output is enabled."""
|
|
73
77
|
return f"{cls._c(cls.RED)}{text}{cls._c(cls.RESET)}"
|
|
74
78
|
|
|
75
79
|
@classmethod
|
|
76
80
|
def bold(cls, text: str) -> str:
|
|
81
|
+
"""Wraps text with ANSI bold weight if color output is enabled."""
|
|
77
82
|
return f"{cls._c(cls.BOLD)}{text}{cls._c(cls.RESET)}"
|
|
78
83
|
|
|
79
84
|
@classmethod
|
|
80
85
|
def dim(cls, text: str) -> str:
|
|
86
|
+
"""Wraps text with ANSI dim intensity if color output is enabled."""
|
|
81
87
|
return f"{cls._c(cls.DIM)}{text}{cls._c(cls.RESET)}"
|
|
82
88
|
|
|
83
89
|
|
|
@@ -85,27 +91,34 @@ class OutputFormatter:
|
|
|
85
91
|
"""Standardized console & machine-readable output renderer."""
|
|
86
92
|
|
|
87
93
|
def __init__(self, quiet: bool = False, json_mode: bool = False, verbose: bool = False):
|
|
94
|
+
"""Initializes the output formatter with verbosity and mode toggles."""
|
|
88
95
|
self.quiet = quiet
|
|
89
96
|
self.json_mode = json_mode
|
|
90
97
|
self.verbose = verbose
|
|
91
98
|
|
|
92
99
|
def debug(self, message: str):
|
|
100
|
+
"""Prints a debug message when verbose mode is active."""
|
|
93
101
|
if self.verbose and not self.quiet and not self.json_mode:
|
|
94
102
|
print(f"{Colors.dim('đ [DEBUG]')} {message}")
|
|
95
103
|
|
|
96
104
|
def info(self, message: str):
|
|
105
|
+
"""Alias for info_msg printing informational text."""
|
|
97
106
|
self.info_msg(message)
|
|
98
107
|
|
|
99
108
|
def warn(self, message: str):
|
|
109
|
+
"""Alias for warn_msg printing warning text."""
|
|
100
110
|
self.warn_msg(message)
|
|
101
111
|
|
|
102
112
|
def error(self, message: str):
|
|
113
|
+
"""Alias for fail_msg printing failure/error text."""
|
|
103
114
|
self.fail_msg(message)
|
|
104
115
|
|
|
105
116
|
def success(self, message: str):
|
|
117
|
+
"""Alias for pass_msg printing passing/success text."""
|
|
106
118
|
self.pass_msg(message)
|
|
107
119
|
|
|
108
120
|
def header(self, title: str):
|
|
121
|
+
"""Renders an eye-catching framed header box for CLI stages."""
|
|
109
122
|
if not self.quiet and not self.json_mode:
|
|
110
123
|
border = "=" * 70
|
|
111
124
|
print(f"\n{Colors.cyan(border)}")
|
|
@@ -113,26 +126,32 @@ class OutputFormatter:
|
|
|
113
126
|
print(f"{Colors.cyan(border)}\n")
|
|
114
127
|
|
|
115
128
|
def step(self, current: int, total: int, title: str):
|
|
129
|
+
"""Prints a numbered step indicator for multi-phase operations."""
|
|
116
130
|
if not self.quiet and not self.json_mode:
|
|
117
131
|
print(f"{Colors.bold(f'[{current}/{total}]')} {title}")
|
|
118
132
|
|
|
119
133
|
def pass_msg(self, message: str):
|
|
134
|
+
"""Prints a green checkmark pass badge with the given message."""
|
|
120
135
|
if not self.json_mode:
|
|
121
136
|
print(f"{Colors.green('â
[PASS]')} {message}")
|
|
122
137
|
|
|
123
138
|
def fail_msg(self, message: str):
|
|
139
|
+
"""Prints a red cross fail badge with the given message."""
|
|
124
140
|
if not self.json_mode:
|
|
125
141
|
print(f"{Colors.red('â [FAIL]')} {message}")
|
|
126
142
|
|
|
127
143
|
def warn_msg(self, message: str):
|
|
144
|
+
"""Prints a yellow warning badge with the given message."""
|
|
128
145
|
if not self.quiet and not self.json_mode:
|
|
129
146
|
print(f"{Colors.yellow('â ī¸ [WARN]')} {message}")
|
|
130
147
|
|
|
131
148
|
def info_msg(self, message: str):
|
|
149
|
+
"""Prints a cyan informational badge with the given message."""
|
|
132
150
|
if not self.quiet and not self.json_mode:
|
|
133
151
|
print(f"{Colors.cyan('âšī¸ [INFO]')} {message}")
|
|
134
152
|
|
|
135
153
|
def print_data(self, data: Any, format_type: str = "text"):
|
|
154
|
+
"""Formats and outputs data payload as either indented JSON or raw text."""
|
|
136
155
|
if format_type == "json" or self.json_mode:
|
|
137
156
|
if isinstance(data, (dict, list)):
|
|
138
157
|
print(json.dumps(data, indent=2, ensure_ascii=False))
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Synapse Hub â Performance, Stress & Flakiness Profilers (tools.perf)
|
|
3
|
+
---------------------------------------------------------------------
|
|
4
|
+
Domain package grouping all JMeter test plan generators, flakiness
|
|
5
|
+
sentinels, BFCL agent gym benchmarks, and test matrix sharders.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from tools import (
|
|
9
|
+
browsergym_eval,
|
|
10
|
+
db_sandbox,
|
|
11
|
+
flaky_detector,
|
|
12
|
+
generate_jmx_plan,
|
|
13
|
+
matrix_sharder,
|
|
14
|
+
synapse_qa_bench,
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
__all__ = [
|
|
18
|
+
"browsergym_eval",
|
|
19
|
+
"db_sandbox",
|
|
20
|
+
"flaky_detector",
|
|
21
|
+
"generate_jmx_plan",
|
|
22
|
+
"matrix_sharder",
|
|
23
|
+
"synapse_qa_bench",
|
|
24
|
+
]
|
|
@@ -15,6 +15,13 @@ import glob
|
|
|
15
15
|
import xml.etree.ElementTree as ET
|
|
16
16
|
import re
|
|
17
17
|
|
|
18
|
+
if hasattr(sys.stdout, 'reconfigure'):
|
|
19
|
+
try:
|
|
20
|
+
sys.stdout.reconfigure(encoding='utf-8')
|
|
21
|
+
sys.stderr.reconfigure(encoding='utf-8')
|
|
22
|
+
except Exception:
|
|
23
|
+
pass
|
|
24
|
+
|
|
18
25
|
def find_latest_report():
|
|
19
26
|
reports = glob.glob("Reports/**/JUnit_Report.xml", recursive=True)
|
|
20
27
|
if not reports:
|
|
@@ -51,7 +58,7 @@ def parse_failures(xml_path):
|
|
|
51
58
|
if reason_match:
|
|
52
59
|
reason = reason_match.group(1).strip()
|
|
53
60
|
else:
|
|
54
|
-
lines = [
|
|
61
|
+
lines = [line.strip() for line in combined.split("\n") if line.strip()]
|
|
55
62
|
reason = lines[0] if lines else "Unknown Error"
|
|
56
63
|
|
|
57
64
|
# Extract Failed Line in Groovy Page / Script
|
|
@@ -70,6 +77,11 @@ def parse_failures(xml_path):
|
|
|
70
77
|
parse_junit_xml = parse_failures
|
|
71
78
|
|
|
72
79
|
def main():
|
|
80
|
+
if len(sys.argv) > 1 and sys.argv[1] in ("-h", "--help"):
|
|
81
|
+
print("Usage: python3 tools/pinpoint_failure.py [path/to/JUnit_Report.xml]")
|
|
82
|
+
print("Scans JUnit XML reports and pinpoints failed test cases and code lines in under 100 tokens.")
|
|
83
|
+
sys.exit(0)
|
|
84
|
+
|
|
73
85
|
xml_path = sys.argv[1] if len(sys.argv) > 1 else find_latest_report()
|
|
74
86
|
if not xml_path:
|
|
75
87
|
print("No JUnit_Report.xml found in Reports/.")
|
package/tools/project_state.py
CHANGED
|
@@ -8,9 +8,7 @@ Enforces a strict Rolling Window (< 50 lines, ~200 tokens) to guarantee zero tok
|
|
|
8
8
|
|
|
9
9
|
import os
|
|
10
10
|
import sys
|
|
11
|
-
import json
|
|
12
11
|
from datetime import datetime
|
|
13
|
-
from pathlib import Path
|
|
14
12
|
|
|
15
13
|
# Enforce UTF-8 stdout encoding for Windows console compatibility
|
|
16
14
|
if hasattr(sys.stdout, 'reconfigure'):
|
|
@@ -164,6 +162,10 @@ def read_state(target_dir):
|
|
|
164
162
|
|
|
165
163
|
|
|
166
164
|
if __name__ == "__main__":
|
|
165
|
+
if len(sys.argv) > 1 and sys.argv[1] in ("-h", "--help"):
|
|
166
|
+
print("Usage: python3 tools/project_state.py [target_dir]")
|
|
167
|
+
print("Initializes or verifies the rolling-window PROJECT_STATE.md anchor in target directory.")
|
|
168
|
+
sys.exit(0)
|
|
167
169
|
target = sys.argv[1] if len(sys.argv) > 1 else os.getcwd()
|
|
168
170
|
sf = init_state(target)
|
|
169
171
|
print(f"Project state anchor initialized at: {sf}")
|