synapse-hub 2.7.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.
Files changed (108) hide show
  1. package/.agents/agents/live-explorer.md +2 -0
  2. package/.agents/agents/pom-crafter.md +2 -0
  3. package/.agents/agents/test-runner.md +3 -0
  4. package/.agents/skills/lean-impact-scoreboard/SKILL.md +1 -1
  5. package/.agents/skills/repo-quality-audit/SKILL.md +1 -1
  6. package/.agents/skills/review-spec/SKILL.md +1 -1
  7. package/.agents/skills/senior-code-review/SKILL.md +1 -1
  8. package/.agents/skills/technical-debt-harvester/SKILL.md +1 -1
  9. package/CLAUDE.md +1 -1
  10. package/README.en.md +70 -291
  11. package/README.md +68 -303
  12. package/docs/ARCHITECTURE.md +48 -2
  13. package/docs/CONTRIBUTING.md +1 -1
  14. package/docs/QUALITY_GATES.md +113 -0
  15. package/package.json +1 -1
  16. package/scripts/package_dist.py +2 -1
  17. package/skills_manifest.json +6 -6
  18. package/synapse.config.json +1 -1
  19. package/templates/ai_bridges/CLAUDE.md +1 -1
  20. package/templates/ai_bridges/copilot-instructions.md +2 -2
  21. package/tools/__init__.py +18 -1
  22. package/tools/_openapi_parser.py +1 -1
  23. package/tools/agent_canary.py +42 -30
  24. package/tools/agentless_patcher.py +2 -2
  25. package/tools/analyze_project.py +3 -5
  26. package/tools/api_drift_sentinel.py +4 -4
  27. package/tools/api_fuzzer.py +8 -8
  28. package/tools/auto_heal.py +4 -5
  29. package/tools/auto_heal_reflexion.py +2 -2
  30. package/tools/autogen_qa_broker.py +2 -2
  31. package/tools/browser_helpers.js +2 -2
  32. package/tools/browsergym_eval.py +2 -3
  33. package/tools/bug_reporter.py +11 -13
  34. package/tools/bump_version.py +75 -5
  35. package/tools/cache_resolver.py +78 -83
  36. package/tools/check_env.py +9 -1
  37. package/tools/check_version_sync.py +40 -3
  38. package/tools/ci_healing_hook.py +4 -6
  39. package/tools/cli.py +5 -7
  40. package/tools/config_decoupler.py +2 -3
  41. package/tools/core/__init__.py +52 -0
  42. package/tools/count_tokens.py +22 -20
  43. package/tools/dashboard_generator.py +627 -998
  44. package/tools/db_sandbox.py +65 -53
  45. package/tools/debt_harvester.py +3 -3
  46. package/tools/distill_log.py +3 -3
  47. package/tools/dspy_qa_signatures.py +3 -4
  48. package/tools/export_postman_collection.py +8 -8
  49. package/tools/flaky_detector.py +2 -2
  50. package/tools/fuzz_payloads.py +5 -5
  51. package/tools/generate_allure_report.py +1 -1
  52. package/tools/generate_jmx_plan.py +4 -4
  53. package/tools/gherkin_suite.py +1 -1
  54. package/tools/git_pre_commit_guard.py +2 -2
  55. package/tools/goldfish_review.py +2 -2
  56. package/tools/heal/__init__.py +28 -0
  57. package/tools/heal_pr_automator.py +6 -6
  58. package/tools/heuristic_locator_matcher.py +2 -2
  59. package/tools/infer_linter.py +8 -8
  60. package/tools/interview_story.py +0 -1
  61. package/tools/jtl_analyzer.py +11 -11
  62. package/tools/lint/__init__.py +30 -0
  63. package/tools/lint_ai_docs.py +42 -0
  64. package/tools/lookup_tc.py +1 -1
  65. package/tools/matrix_sharder.py +15 -13
  66. package/tools/mcp/__init__.py +16 -0
  67. package/tools/mcp_excel_server.py +2 -2
  68. package/tools/mcp_server.py +3 -4
  69. package/tools/md_to_xlsx.py +26 -26
  70. package/tools/micro_mutator.py +11 -12
  71. package/tools/network_mock_shield.py +27 -27
  72. package/tools/newman_analyzer.py +2 -3
  73. package/tools/omni_emitter.py +5 -8
  74. package/tools/omni_parser.py +5 -5
  75. package/tools/omni_transpiler.py +5 -5
  76. package/tools/output_formatter.py +19 -0
  77. package/tools/perf/__init__.py +24 -0
  78. package/tools/pinpoint_failure.py +1 -1
  79. package/tools/project_state.py +0 -2
  80. package/tools/qa_event_stream.py +1 -1
  81. package/tools/repo_map.py +8 -8
  82. package/tools/report/__init__.py +32 -0
  83. package/tools/reversible_sandbox.py +1 -2
  84. package/tools/safety_firewall.py +2 -2
  85. package/tools/senior_code_review.py +2 -2
  86. package/tools/setup_project.py +10 -12
  87. package/tools/skill_collision_guard.py +3 -3
  88. package/tools/skill_vault.py +12 -3
  89. package/tools/skillspector.py +5 -7
  90. package/tools/smart_visual_masker.py +4 -6
  91. package/tools/spec_drift_sentinel.py +1 -2
  92. package/tools/swe_qa_aci.py +2 -2
  93. package/tools/synapse_qa_bench.py +3 -3
  94. package/tools/sync_agent_rules.py +17 -3
  95. package/tools/telemetry_correlator.py +3 -2
  96. package/tools/test_memory_os.py +15 -5
  97. package/tools/textgrad_mutation_optimizer.py +3 -3
  98. package/tools/tms_sync_bridge.py +5 -5
  99. package/tools/tot_exploratory_tester.py +5 -6
  100. package/tools/traffic_session_converter.py +9 -9
  101. package/tools/universal_ir.py +2 -3
  102. package/tools/update_sentinel.py +6 -9
  103. package/tools/verify_all.py +10 -0
  104. package/tools/visual_diff_canvas.py +1 -2
  105. package/tools/visual_som_helper.py +15 -13
  106. package/tools/watch_mode.py +1 -1
  107. package/tools/wcag_audit.py +22 -1
  108. package/tools/welcome_page.py +5 -6
@@ -12,18 +12,15 @@ Supports:
12
12
  5. Cypress JavaScript (cypress-js)
13
13
  """
14
14
 
15
- import os
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, PageClassIR, TestCaseIR, MethodIR, StepIR, LocatorIR,
21
- ActionType, LocatorStrategy, AssertionType
19
+ ProjectIR, ActionType, LocatorStrategy
22
20
  )
23
21
  except ImportError:
24
22
  from universal_ir import (
25
- ProjectIR, PageClassIR, TestCaseIR, MethodIR, StepIR, LocatorIR,
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
- f" const uniqueCode = 'AUTO_' + Date.now();",
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
- f"String uniqueCode = BasePage.uniqueCode('AUTO_')",
445
+ "String uniqueCode = BasePage.uniqueCode('AUTO_')",
449
446
  "",
450
447
  ]
451
448
  for s in tc.steps:
@@ -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
- val = int(sleep_m.group(1))
373
- ms = val * 1000 if val <= 60 else val # WebUI.delay(3) vs Thread.sleep(3000)
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
- type_val = extract_quoted_string(re.search(r"(?:\"([^\"]*)\"|'([^']*)')", cy_args).groups()) if re.search(r"(?:\"([^\"]*)\"|'([^']*)')", cy_args) else ""
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))
@@ -12,15 +12,15 @@ import os
12
12
  import sys
13
13
  import json
14
14
  import argparse
15
- from typing import Dict, List, Any, Optional
15
+ from typing import Dict, Any, Optional
16
16
 
17
17
  # Dynamic imports
18
18
  try:
19
- from tools.universal_ir import ProjectIR, resolve_hermetic_fixtures, analyze_data_dependencies
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 ProjectIR, resolve_hermetic_fixtures, analyze_data_dependencies
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
+ ]
@@ -58,7 +58,7 @@ def parse_failures(xml_path):
58
58
  if reason_match:
59
59
  reason = reason_match.group(1).strip()
60
60
  else:
61
- lines = [l.strip() for l in combined.split("\n") if l.strip()]
61
+ lines = [line.strip() for line in combined.split("\n") if line.strip()]
62
62
  reason = lines[0] if lines else "Unknown Error"
63
63
 
64
64
  # Extract Failed Line in Groovy Page / Script
@@ -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'):
@@ -25,7 +25,7 @@ import json
25
25
  import hashlib
26
26
  import argparse
27
27
  from datetime import datetime, timezone
28
- from typing import Dict, Any, List, Optional, Tuple
28
+ from typing import Dict, Any, Optional
29
29
 
30
30
  # Enforce UTF-8 stdout encoding
31
31
  if hasattr(sys.stdout, 'reconfigure'):
package/tools/repo_map.py CHANGED
@@ -199,13 +199,13 @@ def build_repo_map(target_repo=None, output_txt=None, output_json=None):
199
199
  # Render text map
200
200
  timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
201
201
  out_lines = [
202
- f"# ==============================================================================",
203
- f"# ENTERPRISE AUTOMATION REPOSITORY MAP (Aider-Style AST Compression)",
202
+ "# ==============================================================================",
203
+ "# ENTERPRISE AUTOMATION REPOSITORY MAP (Aider-Style AST Compression)",
204
204
  f"# Generated : {timestamp}",
205
205
  f"# Target : {repo}",
206
206
  f"# Scope : {len(classes)} Classes ({total_raw_lines} source lines, {total_raw_bytes / 1024:.1f} KB)",
207
- f"# Purpose : Token-budgeted index (< 600 tokens) for instant method lookup",
208
- f"# ==============================================================================\n"
207
+ "# Purpose : Token-budgeted index (< 600 tokens) for instant method lookup",
208
+ "# ==============================================================================\n"
209
209
  ]
210
210
 
211
211
  total_methods = 0
@@ -294,9 +294,9 @@ def main():
294
294
  return 1
295
295
 
296
296
  stats = build_repo_map(target_repo=target_repo)
297
- print(f"\n======================================================================")
298
- print(f" Enterprise Repository Map Compressor (Aider-Style AST Map) ")
299
- print(f"======================================================================")
297
+ print("\n======================================================================")
298
+ print(" Enterprise Repository Map Compressor (Aider-Style AST Map) ")
299
+ print("======================================================================")
300
300
  print(f" Target Repository : {stats['target_repo']}")
301
301
  print(f" Indexed Classes : {stats['classes_count']} Page Classes & Helpers")
302
302
  print(f" Extracted Methods : {stats['methods_count']} API signatures")
@@ -304,7 +304,7 @@ def main():
304
304
  print(f" Compressed Map Size : {stats['compressed_bytes'] / 1024:.1f} KB (~{stats['estimated_tokens']} tokens)")
305
305
  print(f" Compression Ratio : {stats['compression_ratio_pct']:.1f}% reduction")
306
306
  print(f" Artifact Generated : {stats['output_file']}")
307
- print(f"======================================================================\n")
307
+ print("======================================================================\n")
308
308
 
309
309
  if args.print:
310
310
  with open(stats['output_file'], "r", encoding="utf-8") as f:
@@ -0,0 +1,32 @@
1
+ """
2
+ Synapse Hub — Reporting & Telemetry Engines (tools.report)
3
+ ----------------------------------------------------------
4
+ Domain package grouping all HTML dashboard, spreadsheet, JTL/Newman
5
+ metric parser, and visual reporting tools.
6
+ """
7
+
8
+ from tools import (
9
+ bug_reporter,
10
+ dashboard_generator,
11
+ generate_allure_report,
12
+ generate_test_reports,
13
+ jtl_analyzer,
14
+ md_to_xlsx,
15
+ newman_analyzer,
16
+ output_formatter,
17
+ telemetry_correlator,
18
+ welcome_page,
19
+ )
20
+
21
+ __all__ = [
22
+ "bug_reporter",
23
+ "dashboard_generator",
24
+ "generate_allure_report",
25
+ "generate_test_reports",
26
+ "jtl_analyzer",
27
+ "md_to_xlsx",
28
+ "newman_analyzer",
29
+ "output_formatter",
30
+ "telemetry_correlator",
31
+ "welcome_page",
32
+ ]
@@ -17,11 +17,10 @@ Reference:
17
17
 
18
18
  import os
19
19
  import sys
20
- import json
21
20
  import shlex
22
21
  import subprocess
23
22
  from dataclasses import dataclass, field
24
- from typing import List, Optional, Callable, Dict, Any
23
+ from typing import List, Optional, Dict, Any
25
24
 
26
25
  # Enforce UTF-8 stdout encoding for Windows console compatibility
27
26
  if hasattr(sys.stdout, 'reconfigure'):
@@ -245,7 +245,7 @@ def detect_action_loop(action_history: List[str], repeat_threshold: int = 4) ->
245
245
  """
246
246
  Detects infinite action loops and repeating cycle patterns among agent tool calls.
247
247
  Inspired by agentblazo/blazo deterministic detection rules.
248
-
248
+
249
249
  Checks:
250
250
  1. Consecutive identical actions (>= repeat_threshold)
251
251
  2. 2-action repeating cycle: [A, B, A, B]
@@ -411,7 +411,7 @@ def main():
411
411
  if all_authorized:
412
412
  print(f"\n✅ All actions cleared by Safety Firewall{' (Dry-Run)' if args.dry_run else ''}.\n")
413
413
  else:
414
- print(f"\n❌ Pre-execution Blocked: Destructive actions intercepted without --force or ALLOW_DESTRUCTIVE=1.\n")
414
+ print("\n❌ Pre-execution Blocked: Destructive actions intercepted without --force or ALLOW_DESTRUCTIVE=1.\n")
415
415
 
416
416
  return 0 if all_authorized else 1
417
417
 
@@ -28,7 +28,7 @@ import re
28
28
  import json
29
29
  import subprocess
30
30
  import argparse
31
- from typing import Dict, List, Any, Optional, Tuple
31
+ from typing import Dict, List, Any, Tuple
32
32
 
33
33
  if hasattr(sys.stdout, 'reconfigure'):
34
34
  try:
@@ -83,7 +83,7 @@ def get_git_diff(repo_dir: str, target: str = "uncommitted") -> str:
83
83
  check=True
84
84
  )
85
85
  return res.stdout
86
- except Exception as e:
86
+ except Exception:
87
87
  return ""
88
88
 
89
89
 
@@ -24,7 +24,6 @@ import json
24
24
  import shutil
25
25
  import argparse
26
26
  from pathlib import Path
27
- from datetime import datetime
28
27
 
29
28
  # Enforce UTF-8 stdout encoding for Windows console compatibility
30
29
  if hasattr(sys.stdout, 'reconfigure'):
@@ -39,9 +38,8 @@ HUB_ROOT = os.path.abspath(os.path.join(SCRIPT_DIR, ".."))
39
38
  TEMPLATES_DIR = os.path.join(HUB_ROOT, "templates")
40
39
  sys.path.insert(0, SCRIPT_DIR)
41
40
 
42
- import analyze_project
43
- import verify_all
44
- import project_state
41
+ import analyze_project # noqa: E402
42
+ import project_state # noqa: E402
45
43
 
46
44
  GREEN = "\033[92m"
47
45
  RED = "\033[91m"
@@ -412,7 +410,7 @@ def inject_antigravity_global_plugin():
412
410
  try:
413
411
  os.unlink(dst)
414
412
  except OSError:
415
- unlinked = False
413
+ _ = False
416
414
  if sys.platform == "win32":
417
415
  try:
418
416
  import _winapi
@@ -420,7 +418,7 @@ def inject_antigravity_global_plugin():
420
418
  _winapi.CreateJunction(src, dst)
421
419
  return
422
420
  except (OSError, ImportError, AttributeError):
423
- junction_created = False
421
+ _ = False
424
422
  shutil.copytree(src, dst, dirs_exist_ok=True, ignore=shutil.ignore_patterns("__pycache__", "*.pyc", "*.tmp"))
425
423
 
426
424
  sync_dir(os.path.join(HUB_ROOT, ".agents", "skills"), os.path.join(target_plugin_dir, "skills"))
@@ -612,26 +610,26 @@ def run_setup(target_repo, dry_run=False, profile="auto", no_global=True, no_git
612
610
  if dry_run:
613
611
  print(f"Operational Mode : {YELLOW}DRY-RUN (Simulating without modifying files on disk){RESET}\n")
614
612
  else:
615
- print(f"Operational Mode : APPLY CHANGES\n")
613
+ print("Operational Mode : APPLY CHANGES\n")
616
614
 
617
615
  if dry_run:
618
616
  print(f"{YELLOW}[DRY-RUN PREVIEW]{RESET}")
619
617
  print(f" • Profile: {profile.upper()}")
620
618
  print(f" • Would generate: {os.path.join(target_repo, 'PROJECT_AI_GUIDE.md')}")
621
- print(f" • Would deploy AI bridges: .cursor/rules/synapse-qa.mdc, .github/copilot-instructions.md, .windsurfrules")
619
+ print(" • Would deploy AI bridges: .cursor/rules/synapse-qa.mdc, .github/copilot-instructions.md, .windsurfrules")
622
620
  print(f" • Would install pre-push hook: {os.path.join(target_repo, '.git', 'hooks', 'pre-push')}")
623
- print(f" • Would initialize: Central Agent Memory (~/.agent_memory/global_cache.db)")
621
+ print(" • Would initialize: Central Agent Memory (~/.agent_memory/global_cache.db)")
624
622
  print(f"\n{GREEN}✅ Dry-run completed successfully. Zero changes written to disk.{RESET}\n")
625
623
  return 0
626
624
 
627
625
  # 2. Ensure PROJECT_AI_GUIDE.md & PROJECT_STATE.md
628
626
  print(f"{BOLD}[1/5] Checking Project AI Guide & State Anchor...{RESET}")
629
- guide_created = ensure_project_ai_guide(target_repo, stack_info, profile=profile)
627
+ ensure_project_ai_guide(target_repo, stack_info, profile=profile)
630
628
  project_state.init_state(target_repo)
631
629
 
632
630
  # 3. Deploy Universal AI Bridges (Cursor, Claude Code, GitHub Copilot, Windsurf)
633
631
  print(f"\n{BOLD}[2/5] Deploying Universal AI Bridges (Cursor, Claude, Copilot, Windsurf)...{RESET}")
634
- bridges_deployed = install_universal_ai_bridges(target_repo)
632
+ install_universal_ai_bridges(target_repo)
635
633
 
636
634
  # 4. Inject Antigravity Global Plugin
637
635
  plugin_injected = False
@@ -687,7 +685,7 @@ def run_setup(target_repo, dry_run=False, profile="auto", no_global=True, no_git
687
685
  print(f" Target Framework : {stack_info['framework']}")
688
686
  print(f" Active Profile : {profile.upper()}")
689
687
  print(f" AI Project Guide : {os.path.join(target_repo, 'PROJECT_AI_GUIDE.md')}")
690
- print(f" Universal Bridges : Cursor (.cursor/rules), Claude Code, Copilot, Windsurf")
688
+ print(" Universal Bridges : Cursor (.cursor/rules), Claude Code, Copilot, Windsurf")
691
689
  print(f" Antigravity Plugin : {'ACTIVE (~/.gemini/config/plugins/synapse-hub)' if plugin_injected else 'STANDALONE'}")
692
690
  print(f" AST Method Map : {os.path.join(target_repo, 'repo_map.txt')}")
693
691
  print(f" Health Report : {os.path.join(target_repo, 'PROJECT_HEALTH_REPORT.md')}")
@@ -23,8 +23,8 @@ import sys
23
23
  import re
24
24
  import math
25
25
  import json
26
+ from typing import Dict, List, Tuple, Any
26
27
  import argparse
27
- from typing import Dict, List, Tuple
28
28
  from collections import Counter
29
29
 
30
30
  # Enforce UTF-8 stdout encoding for Windows console compatibility
@@ -136,7 +136,7 @@ class SkillCollisionGuard:
136
136
  fallback_name = os.path.basename(os.path.dirname(path))
137
137
  return fallback_name, ""
138
138
 
139
- def audit(self) -> Tuple[bool, List[Dict[str, any]]]:
139
+ def audit(self) -> Tuple[bool, List[Dict[str, Any]]]:
140
140
  """
141
141
  Computes pairwise similarity.
142
142
  Returns (is_clean, report_items).
@@ -211,7 +211,7 @@ def run_guard(skills_dir: str = ".agents/skills", threshold: float = 0.75, warn_
211
211
  print("=" * 70 + "\n")
212
212
  return 1
213
213
 
214
- print(f"\n✅ [PASS] 0 routing collisions detected. All skill descriptions uniquely segmented.\n")
214
+ print("\n✅ [PASS] 0 routing collisions detected. All skill descriptions uniquely segmented.\n")
215
215
  print("=" * 70 + "\n")
216
216
  return 0
217
217
 
@@ -22,7 +22,7 @@ import json
22
22
  import re
23
23
  import difflib
24
24
  import argparse
25
- from dataclasses import dataclass, asdict
25
+ from dataclasses import dataclass
26
26
  from typing import List, Optional, Dict, Any, Set
27
27
 
28
28
  # Enforce UTF-8 stdout encoding for Windows console compatibility
@@ -101,6 +101,15 @@ class PageClassPrimitive:
101
101
  tags: str = "" # Comma-separated domain tags, e.g. "auth,sso,login"
102
102
 
103
103
 
104
+ class ManagedConnection(sqlite3.Connection):
105
+ """SQLite connection that automatically commits/rollbacks and closes on context exit."""
106
+ def __exit__(self, exc_type, exc_val, exc_tb):
107
+ try:
108
+ super().__exit__(exc_type, exc_val, exc_tb)
109
+ finally:
110
+ self.close()
111
+
112
+
104
113
  class SkillVault:
105
114
  """Persistent library of verified, self-contained Page Class methods."""
106
115
 
@@ -113,8 +122,8 @@ class SkillVault:
113
122
  self.db_path = db_path
114
123
  self._init_schema()
115
124
 
116
- def _get_connection(self) -> sqlite3.Connection:
117
- conn = sqlite3.connect(self.db_path)
125
+ def _get_connection(self) -> ManagedConnection:
126
+ conn = sqlite3.connect(self.db_path, factory=ManagedConnection)
118
127
  conn.row_factory = sqlite3.Row
119
128
  return conn
120
129
 
@@ -42,17 +42,15 @@ Usage:
42
42
  from __future__ import annotations
43
43
 
44
44
  import ast
45
- import fnmatch
46
45
  import hashlib
47
46
  import json
48
47
  import os
49
48
  import re
50
49
  import sys
51
- import unicodedata
52
50
  from dataclasses import dataclass, field
53
51
  from enum import Enum
54
52
  from pathlib import Path
55
- from typing import Any, Dict, List, Optional, Set, Tuple
53
+ from typing import Any, Dict, List, Tuple
56
54
 
57
55
  # Enforce UTF-8 stdout encoding for Windows console compatibility
58
56
  if hasattr(sys.stdout, "reconfigure"):
@@ -529,9 +527,9 @@ def scan_text_patterns(file_path: str, content: str) -> List[Finding]:
529
527
  # Line number offset indexing
530
528
  line_offsets = []
531
529
  curr = 0
532
- for l in lines:
530
+ for line_str in lines:
533
531
  line_offsets.append(curr)
534
- curr += len(l)
532
+ curr += len(line_str)
535
533
 
536
534
  def get_line_num(char_idx: int) -> int:
537
535
  for idx, offset in enumerate(line_offsets):
@@ -925,7 +923,7 @@ def scan_file(file_path: str) -> List[Finding]:
925
923
  try:
926
924
  with open(file_path, "r", encoding="utf-8", errors="ignore") as f:
927
925
  content = f.read()
928
- except Exception as e:
926
+ except Exception:
929
927
  return []
930
928
 
931
929
  findings: List[Finding] = []
@@ -1013,7 +1011,7 @@ def format_terminal(report: ScanReport) -> str:
1013
1011
  out.append(f"{BOLD}{CYAN}======================================================================{RESET}")
1014
1012
  out.append(f"📁 Target Scope : {report.target_path}")
1015
1013
  out.append(f"📄 Scanned Files : {report.scanned_files}")
1016
- out.append(f"🛡️ Engine Source : NVIDIA/SkillSpector Spec (71 Patterns, 17 Categories)")
1014
+ out.append("🛡️ Engine Source : NVIDIA/SkillSpector Spec (71 Patterns, 17 Categories)")
1017
1015
 
1018
1016
  rec_color = GREEN if report.recommendation == Recommendation.SAFE else (YELLOW if report.recommendation == Recommendation.CAUTION else RED)
1019
1017
  out.append(f"\n{BOLD}🎯 AUDIT VERDICT :{RESET} {rec_color}{BOLD}{report.recommendation.value}{RESET}")
@@ -7,11 +7,9 @@ Automatically disables dynamic CSS animations, freezes SVG spinners,
7
7
  and masks fluctuating UI elements (timestamps, clocks, avatars, ad banners).
8
8
  """
9
9
 
10
- import os
11
- import re
12
10
  import json
13
11
  import argparse
14
- from typing import List, Dict, Any, Tuple
12
+ from typing import List, Optional
15
13
 
16
14
 
17
15
  class SmartVisualMasker:
@@ -56,13 +54,13 @@ class SmartVisualMasker:
56
54
  return cls.ANTI_FLAKE_CSS.strip()
57
55
 
58
56
  @classmethod
59
- def generate_playwright_ts_options(cls, additional_selectors: List[str] = None) -> str:
57
+ def generate_playwright_ts_options(cls, additional_selectors: Optional[List[str]] = None) -> str:
60
58
  """
61
59
  Generates Playwright TypeScript assertion options with masking and disabled animations.
62
60
  """
63
61
  selectors = cls.DEFAULT_MASK_SELECTORS + (additional_selectors or [])
64
62
  locators_ts = ",\n ".join([f"page.locator('{sel}')" for sel in selectors])
65
-
63
+
66
64
  return f"""await expect(page).toHaveScreenshot('visual-baseline.png', {{
67
65
  animations: 'disabled',
68
66
  caret: 'hide',
@@ -74,7 +72,7 @@ class SmartVisualMasker:
74
72
  }});"""
75
73
 
76
74
  @classmethod
77
- def generate_browser_mask_script(cls, selectors: List[str] = None) -> str:
75
+ def generate_browser_mask_script(cls, selectors: Optional[List[str]] = None) -> str:
78
76
  """
79
77
  Generates JavaScript snippet to run inside the live browser
80
78
  to immediately freeze DOM animations and paint solid black masks
@@ -206,7 +206,6 @@ def compute_drift(spec_criteria: List[Dict[str, Any]], code_files: List[Tuple[st
206
206
  all_code_actions.extend([(file_path, a) for a in actions])
207
207
  combined_code += "\n" + content
208
208
 
209
- combined_code_lower = combined_code.lower()
210
209
  code_tokens = tokenize_text(combined_code)
211
210
 
212
211
  covered_criteria = []
@@ -289,7 +288,7 @@ def generate_markdown_report(result: Dict[str, Any], spec_file: str, code_path:
289
288
  md.append("> Generated autonomously by Synapse-Hub `tools/spec_drift_sentinel.py` ")
290
289
  md.append(f"> **Specification:** `{spec_file}` | **Code Target:** `{code_path}` \n")
291
290
  md.append("---")
292
-
291
+
293
292
  status_icon = "✅" if result["passed"] else "❌"
294
293
  md.append(f"## 📊 Executive Summary: {status_icon} [{result['status']}]")
295
294
  md.append(f"- **Alignment Score:** `{result['alignment_score']}%` (Pass threshold: >= 80% & zero Deficit Drift)")
@@ -216,8 +216,8 @@ class SweQaAci:
216
216
  f.write(new_content)
217
217
 
218
218
  # Diff summary formatting
219
- target_lines = [f"- {l}" for l in norm_target.splitlines()]
220
- replacement_lines = [f"+ {l}" for l in norm_replacement.splitlines()]
219
+ target_lines = [f"- {line}" for line in norm_target.splitlines()]
220
+ replacement_lines = [f"+ {line}" for line in norm_replacement.splitlines()]
221
221
  diff_summary = "\n".join(target_lines + replacement_lines)
222
222
 
223
223
  return {