synapse-hub 2.2.3 → 2.4.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 +11 -0
- package/.agents/agents/live-explorer.md +28 -0
- package/.agents/agents/orchestrator.md +20 -4
- package/.agents/agents/pom-crafter.md +12 -0
- package/.agents/agents/quality-gatekeeper.md +19 -4
- package/.agents/agents/test-runner.md +11 -0
- package/.agents/rules/communication-style.md +40 -0
- package/.agents/rules/context-engineering.md +23 -0
- package/.agents/rules/git-push-protocol.md +11 -17
- package/.agents/rules/graphify.md +14 -14
- package/.agents/rules/lessons-learned.md +3 -3
- package/.agents/rules/mandatory-playwright-live.md +29 -29
- package/.agents/rules/mobile_appium_rules.md +132 -0
- package/.agents/rules/performance_testing_rules.md +74 -0
- package/.agents/rules/skill-precedence.md +1 -1
- package/.agents/rules/systematic-debugging.md +6 -6
- package/.agents/skills/agent-orchestration-multi-agent-optimize/SKILL.md +64 -215
- package/.agents/skills/agent-orchestration-multi-agent-optimize/examples/swarm_workload_config.json +12 -0
- package/.agents/skills/antigravity-test-sentinel/SKILL.md +3 -3
- package/.agents/skills/antigravity-test-sentinel/examples/dod_gate_policy.json +11 -0
- package/.agents/skills/api-network-mocking-interception/SKILL.md +1 -1
- package/.agents/skills/api-network-mocking-interception/examples/network_route_stub.json +9 -0
- package/.agents/skills/api-spec-to-e2e-matrix/SKILL.md +9 -9
- package/.agents/skills/api-spec-to-e2e-matrix/examples/sample_openapi.json +19 -0
- package/.agents/skills/architecture-decision-records/SKILL.md +35 -412
- package/.agents/skills/architecture-decision-records/examples/0001-record-architecture-decisions.md +12 -0
- package/.agents/skills/auth-session-and-cookie-manager/SKILL.md +4 -1
- package/.agents/skills/auth-session-and-cookie-manager/examples/storage_state_sample.json +11 -0
- package/.agents/skills/backend-load-and-stress-patterns/SKILL.md +80 -186
- package/.agents/skills/backend-load-and-stress-patterns/examples/k6_load_test_sample.js +13 -0
- package/.agents/skills/bats-testing-patterns/SKILL.md +1 -1
- package/.agents/skills/bats-testing-patterns/examples/cli_runner_test.bats +6 -0
- package/.agents/skills/bats-testing-patterns/resources/implementation-playbook.md +614 -614
- package/.agents/skills/clean-pom-crafter/SKILL.md +21 -3
- package/.agents/skills/clean-pom-crafter/examples/standard_test_case.groovy +28 -28
- package/.agents/skills/clean-pom-crafter/references/pom_patterns.groovy +138 -138
- package/.agents/skills/code-refactoring-refactor-clean/SKILL.md +2 -2
- package/.agents/skills/code-refactoring-refactor-clean/examples/refactored_page_sample.groovy +9 -0
- package/.agents/skills/code-refactoring-refactor-clean/resources/implementation-playbook.md +9 -7
- package/.agents/skills/db-state-verifier-and-seeder/SKILL.md +5 -5
- package/.agents/skills/db-state-verifier-and-seeder/examples/db_fixture_seed.json +12 -0
- package/.agents/skills/e2e-testing-patterns/SKILL.md +1 -1
- package/.agents/skills/e2e-testing-patterns/examples/playwright_sharded_config.ts +12 -0
- package/.agents/skills/e2e-testing-patterns/resources/implementation-playbook.md +522 -522
- package/.agents/skills/failure-autopsy-and-healing/SKILL.md +17 -3
- package/.agents/skills/failure-autopsy-and-healing/examples/sample_junit_failure.xml +8 -0
- package/.agents/skills/failure-autopsy-and-healing/references/healing_matrix.md +64 -64
- package/.agents/skills/failure-autopsy-and-healing/references/qa_investigation_protocol.md +56 -56
- package/.agents/skills/failure-autopsy-and-healing/scripts/triage_failures.sh +98 -98
- package/.agents/skills/file-and-report-validator/SKILL.md +1 -1
- package/.agents/skills/file-and-report-validator/examples/sample_export_schema.json +14 -0
- package/.agents/skills/flaky-test-sentinel-and-quarantine/SKILL.md +3 -3
- package/.agents/skills/flaky-test-sentinel-and-quarantine/examples/quarantine_registry.json +11 -0
- package/.agents/skills/gherkin-to-suite/SKILL.md +103 -0
- package/.agents/skills/gherkin-to-suite/examples/checkout.feature +39 -0
- package/.agents/skills/gherkin-to-suite/examples/suite_report_sample.json +334 -0
- package/.agents/skills/github-actions-templates/SKILL.md +47 -304
- package/.agents/skills/github-actions-templates/examples/matrix_test_pipeline.yml +8 -0
- package/.agents/skills/graphify-impact-analyzer/SKILL.md +6 -6
- package/.agents/skills/graphify-impact-analyzer/examples/dependency_blast_radius.json +8 -0
- package/.agents/skills/katalon-cli-runner/SKILL.md +2 -2
- package/.agents/skills/katalon-cli-runner/examples/headless_kre_exec.sh +3 -0
- package/.agents/skills/katalon-cli-runner/references/groovy-patterns.md +209 -209
- package/.agents/skills/katalon-cli-runner/references/katalon-api.md +155 -155
- package/.agents/skills/katalon-cli-runner/references/runner_commands.md +67 -67
- package/.agents/skills/lam-script-generator/SKILL.md +42 -1
- package/.agents/skills/lam-script-generator/examples/user_story_sample.md +8 -0
- package/.agents/skills/lean-code-ladder/SKILL.md +83 -0
- package/.agents/skills/lean-code-ladder/examples/ladder_walkthrough.md +37 -0
- package/.agents/skills/meta-prompt-crafter/SKILL.md +107 -0
- package/.agents/skills/meta-prompt-crafter/examples/qa_prompt_template.md +35 -0
- package/.agents/skills/persistent-planning-files/SKILL.md +108 -0
- package/.agents/skills/persistent-planning-files/examples/task_plan_example.md +56 -0
- package/.agents/skills/playwright-live-interaction/SKILL.md +49 -1
- package/.agents/skills/playwright-live-interaction/examples/live_probe_script.js +5 -0
- package/.agents/skills/playwright-live-interaction/references/advanced_superpowers.md +160 -160
- package/.agents/skills/playwright-live-interaction/references/compact_accessibility_snapshots.md +75 -75
- package/.agents/skills/playwright-live-interaction/references/recipes.md +388 -388
- package/.agents/skills/playwright-live-interaction/references/swarm_orchestration.md +134 -134
- package/.agents/skills/playwright-webapp-testing/SKILL.md +93 -0
- package/.agents/skills/playwright-webapp-testing/examples/server_lifecycle_playwright.py +63 -0
- package/.agents/skills/rbt-manual-testing/SKILL.md +150 -0
- package/.agents/skills/rbt-manual-testing/examples/checkout_rbt_manual_suite.md +25 -0
- package/.agents/skills/security-dast-sentinel/SKILL.md +57 -135
- package/.agents/skills/security-dast-sentinel/examples/dast_scan_config.json +10 -0
- package/.agents/skills/self-healing-locator/SKILL.md +24 -10
- package/.agents/skills/self-healing-locator/examples/aom_diff_sample.json +16 -0
- package/.agents/skills/skillspector-security-guard/SKILL.md +32 -90
- package/.agents/skills/skillspector-security-guard/examples/safe_mcp_config.json +12 -0
- package/.agents/skills/surgical-coding-principles/SKILL.md +89 -0
- package/.agents/skills/surgical-coding-principles/examples/surgical_vs_scope_creep.md +46 -0
- package/.agents/skills/synthetic-test-data-generator/SKILL.md +3 -3
- package/.agents/skills/synthetic-test-data-generator/examples/idempotent_data_recipe.json +9 -0
- package/.agents/skills/systematic-debugging/SKILL.md +100 -0
- package/.agents/skills/systematic-debugging/examples/four_phase_case.md +44 -0
- package/.agents/skills/test-driven-development/SKILL.md +114 -0
- package/.agents/skills/test-driven-development/examples/red_green_refactor_qa.md +78 -0
- package/.agents/skills/token-and-context-optimizer/SKILL.md +1 -1
- package/.agents/skills/token-and-context-optimizer/examples/distilled_log_sample.txt +3 -0
- package/.agents/skills/verification-before-completion/SKILL.md +100 -0
- package/.agents/skills/verification-before-completion/examples/evidence_log_example.md +46 -0
- package/.agents/skills/visual-regression-sentinel/SKILL.md +21 -1
- package/.agents/skills/visual-regression-sentinel/examples/visual_mask_rules.json +9 -0
- package/.agents/skills/wcag-audit-patterns/SKILL.md +3 -3
- package/.agents/skills/wcag-audit-patterns/examples/wcag_compliance_checklist.json +10 -0
- package/.agents/skills/wcag-audit-patterns/resources/implementation-playbook.md +541 -541
- package/.agents/skills/web-vitals-and-performance-profiler/SKILL.md +1 -1
- package/.agents/skills/web-vitals-and-performance-profiler/examples/cwv_budget_policy.json +6 -0
- package/.agents/templates/completion_report.md +57 -57
- package/.agents/workflows/analyze_requirement_document.md +18 -0
- package/.agents/workflows/export_testcases_excel.md +32 -0
- package/.agents/workflows/generate_combinatorial_test_data.md +28 -0
- package/.agents/workflows/generate_cross_module_test_plan.md +37 -0
- package/.agents/workflows/generate_manual_testcases_rbt.md +56 -0
- package/.agents/workflows/generate_requirements_from_website.md +25 -0
- package/.agents/workflows/generate_testcases_from_requirements.md +21 -0
- package/.agents/workflows/graphify.md +10 -10
- package/.agents/workflows/verify.md +2 -2
- package/.cursor/rules/language.mdc +7 -7
- package/.cursor/rules/synapse-qa.mdc +23 -0
- package/.cursorrules +7 -0
- package/.pre-commit-hooks.yaml +14 -0
- package/.windsurfrules +7 -0
- package/AGENTS.md +54 -15
- package/CLAUDE.md +35 -12
- package/LICENSE +30 -0
- package/NOTICE +180 -0
- package/README.en.md +325 -0
- package/README.md +247 -512
- package/action.yml +51 -0
- package/benchmarks/qa_eval/README.md +71 -0
- package/benchmarks/qa_eval/build_dataset.py +677 -0
- package/benchmarks/qa_eval/dataset/api_contract_drift/qa-challenge-06_api_contract_drift.json +22 -0
- package/benchmarks/qa_eval/dataset/api_contract_drift/qa-challenge-07_api_contract_drift.json +22 -0
- package/benchmarks/qa_eval/dataset/api_contract_drift/qa-challenge-08_api_contract_drift.json +22 -0
- package/benchmarks/qa_eval/dataset/api_contract_drift/qa-challenge-09_api_contract_drift.json +22 -0
- package/benchmarks/qa_eval/dataset/api_contract_drift/qa-challenge-10_api_contract_drift.json +22 -0
- package/benchmarks/qa_eval/dataset/fake_pass_tautology/qa-challenge-21_fake_pass_tautology.json +21 -0
- package/benchmarks/qa_eval/dataset/fake_pass_tautology/qa-challenge-22_fake_pass_tautology.json +21 -0
- package/benchmarks/qa_eval/dataset/fake_pass_tautology/qa-challenge-23_fake_pass_tautology.json +21 -0
- package/benchmarks/qa_eval/dataset/fake_pass_tautology/qa-challenge-24_fake_pass_tautology.json +21 -0
- package/benchmarks/qa_eval/dataset/fake_pass_tautology/qa-challenge-25_fake_pass_tautology.json +21 -0
- package/benchmarks/qa_eval/dataset/locator_drift/qa-challenge-01_locator_drift.json +23 -0
- package/benchmarks/qa_eval/dataset/locator_drift/qa-challenge-02_locator_drift.json +23 -0
- package/benchmarks/qa_eval/dataset/locator_drift/qa-challenge-03_locator_drift.json +23 -0
- package/benchmarks/qa_eval/dataset/locator_drift/qa-challenge-04_locator_drift.json +23 -0
- package/benchmarks/qa_eval/dataset/locator_drift/qa-challenge-05_locator_drift.json +23 -0
- package/benchmarks/qa_eval/dataset/stale_and_mutation/qa-challenge-16_stale_and_mutation.json +22 -0
- package/benchmarks/qa_eval/dataset/stale_and_mutation/qa-challenge-17_stale_and_mutation.json +22 -0
- package/benchmarks/qa_eval/dataset/stale_and_mutation/qa-challenge-18_stale_and_mutation.json +22 -0
- package/benchmarks/qa_eval/dataset/stale_and_mutation/qa-challenge-19_stale_and_mutation.json +22 -0
- package/benchmarks/qa_eval/dataset/stale_and_mutation/qa-challenge-20_stale_and_mutation.json +23 -0
- package/benchmarks/qa_eval/dataset/timing_and_race/qa-challenge-11_timing_and_race.json +22 -0
- package/benchmarks/qa_eval/dataset/timing_and_race/qa-challenge-12_timing_and_race.json +22 -0
- package/benchmarks/qa_eval/dataset/timing_and_race/qa-challenge-13_timing_and_race.json +22 -0
- package/benchmarks/qa_eval/dataset/timing_and_race/qa-challenge-14_timing_and_race.json +22 -0
- package/benchmarks/qa_eval/dataset/timing_and_race/qa-challenge-15_timing_and_race.json +22 -0
- package/benchmarks/qa_eval/eval_runner.py +418 -0
- package/benchmarks/qa_eval/reports/AB_METHODOLOGY_REPORT.md +83 -0
- package/benchmarks/qa_eval/reports/BENCHMARK_REPORT.md +69 -0
- package/benchmarks/qa_eval/reports/eval_results.json +105 -0
- package/bin/agent-qa.js +10 -3
- package/docs/ARCHITECTURE.md +107 -0
- package/docs/CI_CD_INTEGRATION.md +94 -0
- package/docs/CLI_REFERENCE.md +157 -0
- package/docs/CONTRIBUTING.md +91 -0
- package/docs/PLUGIN_DEVELOPMENT_GUIDE.md +126 -0
- package/docs/TOKEN_QUOTA_PLAYBOOK.md +41 -0
- package/docs/adopted-ecosystem-tools.md +87 -0
- package/docs/schemas/synapse.config.schema.json +64 -0
- package/examples/cypress-ecommerce-suite/README.md +45 -0
- package/examples/cypress-ecommerce-suite/cypress/e2e/checkout.cy.js +17 -0
- package/examples/cypress-ecommerce-suite/cypress/pages/BasePage.js +29 -0
- package/examples/cypress-ecommerce-suite/cypress/pages/CartPage.js +51 -0
- package/examples/cypress-ecommerce-suite/cypress.config.js +13 -0
- package/examples/cypress-ecommerce-suite/package.json +13 -0
- package/examples/katalon-suite/Keywords/pages/BasePage.groovy +19 -0
- package/examples/katalon-suite/Keywords/pages/DashboardPage.groovy +29 -0
- package/examples/katalon-suite/Keywords/pages/LoginPage.groovy +45 -0
- package/examples/katalon-suite/Profiles/default.glbl +12 -0
- package/examples/katalon-suite/README.md +18 -0
- package/examples/katalon-suite/Scripts/Auth/TC_LoginSuccess/Script1234567890.groovy +12 -0
- package/examples/katalon-suite/Scripts/Dashboard/TC_ViewSummary/Script1234567891.groovy +15 -0
- package/examples/katalon-suite/katalon_suite.prj +21 -0
- package/examples/playwright-crm-suite/README.md +40 -0
- package/examples/playwright-crm-suite/package.json +14 -0
- package/examples/playwright-crm-suite/pages/BasePage.ts +37 -0
- package/examples/playwright-crm-suite/pages/CustomerPage.ts +57 -0
- package/examples/playwright-crm-suite/pages/LoginPage.ts +32 -0
- package/examples/playwright-crm-suite/playwright.config.ts +27 -0
- package/examples/playwright-crm-suite/tests/auth.spec.ts +22 -0
- package/examples/playwright-crm-suite/tests/customers.spec.ts +33 -0
- package/examples/plugins/sample-custom-plugin/README.md +14 -0
- package/examples/plugins/sample-custom-plugin/plugin.json +16 -0
- package/examples/plugins/sample-custom-plugin/skills/custom-security-headers-audit/SKILL.md +29 -0
- package/examples/plugins/sample-custom-plugin/skills/custom-security-headers-audit/examples/audit_fixture.json +8 -0
- package/examples/plugins/sample-custom-plugin/tools/custom_security_headers.py +125 -0
- package/examples/practices/README.md +22 -0
- package/examples/practices/requirements/crm/requirements_contracts.md +292 -0
- package/examples/practices/requirements/crm/requirements_customers.md +462 -0
- package/examples/practices/requirements/crm/requirements_login.md +202 -0
- package/examples/practices/requirements/crm/requirements_projects.md +396 -0
- package/examples/practices/requirements/crm/requirements_tasks.md +343 -0
- package/examples/practices/requirements/ecommerce/requirements_category_brand.txt +402 -0
- package/examples/practices/requirements/jira/KAN-5/KAN-1/2026-04-03_04-28-27.png +0 -0
- package/examples/practices/requirements/jira/KAN-5/KAN-1/KAN-1_requirement.md +52 -0
- package/examples/practices/requirements/jira/KAN-5/KAN-4/2026-04-03_04-28-19.png +0 -0
- package/examples/practices/requirements/jira/KAN-5/KAN-4/2026-04-03_04-28-57.png +0 -0
- package/examples/practices/requirements/jira/KAN-5/KAN-4/KAN-4_requirement.md +119 -0
- package/examples/practices/requirements/jira/KAN-5/KAN-5_overview.md +9 -0
- package/examples/practices/requirements/jira/KAN-5/KAN-6/2026-04-03_05-58-08.png +0 -0
- package/examples/practices/requirements/jira/KAN-5/KAN-6/2026-04-03_05-58-23.png +0 -0
- package/examples/practices/requirements/jira/KAN-5/KAN-6/KAN-6_requirement.md +32 -0
- package/examples/practices/testcases/api/book_management_api_test_cases.md +144 -0
- package/examples/practices/testcases/api/user_management_api_test_cases.md +139 -0
- package/examples/practices/testcases/crm/test_cases_crm_login.md +148 -0
- package/examples/practices/testcases/crm/test_cases_customers.md +156 -0
- package/examples/pytest-api-suite/README.md +45 -0
- package/examples/pytest-api-suite/conftest.py +31 -0
- package/examples/pytest-api-suite/pages/user_api_client.py +36 -0
- package/examples/pytest-api-suite/requirements.txt +2 -0
- package/examples/pytest-api-suite/tests/test_user_api.py +44 -0
- package/examples/selenium-suite/README.md +18 -0
- package/examples/selenium-suite/pages/base_page.py +27 -0
- package/examples/selenium-suite/pages/login_page.py +29 -0
- package/examples/selenium-suite/pages/order_page.py +25 -0
- package/examples/selenium-suite/pytest.ini +6 -0
- package/examples/selenium-suite/requirements.txt +2 -0
- package/examples/selenium-suite/tests/test_login.py +10 -0
- package/examples/selenium-suite/tests/test_order.py +10 -0
- package/package.json +22 -7
- package/scripts/generate_skill_examples.py +244 -0
- package/scripts/install.ps1 +112 -0
- package/scripts/install_global_plugin.ps1 +94 -0
- package/scripts/install_global_plugin.sh +49 -0
- package/scripts/lint_skills.ps1 +57 -0
- package/scripts/package_dist.py +323 -0
- package/scripts/setup.sh +59 -0
- package/scripts/update_hub.ps1 +19 -0
- package/scripts/update_hub.sh +15 -0
- package/skills_manifest.json +209 -6
- package/synapse.config.json +30 -0
- package/templates/PROJECT_AI_GUIDE_TEMPLATE.md +7 -7
- package/templates/PROJECT_STATE_TEMPLATE.md +1 -1
- package/templates/ai_bridges/CLAUDE.md +33 -16
- package/templates/ai_bridges/copilot-instructions.md +14 -21
- package/templates/ai_bridges/cursor_synapse_qa.mdc +17 -20
- package/templates/ai_bridges/windsurfrules +21 -21
- package/templates/ci/github-actions-synapse.yml +71 -4
- package/templates/welcome.html.tmpl +1674 -0
- package/tools/.infer_baseline.json +1102 -0
- package/tools/TOOLS_RUNBOOK.md +92 -130
- package/tools/__init__.py +26 -0
- package/tools/agent_canary.py +501 -501
- package/tools/analyze_project.py +31 -17
- package/tools/api_fuzzer.py +278 -6
- package/tools/author_integrity.py +6 -6
- package/tools/auto_heal.py +1 -1
- package/tools/browser_helpers.js +105 -7
- package/tools/bug_reporter.py +31 -1
- package/tools/bump_version.py +23 -3
- package/tools/cache_resolver.py +248 -14
- package/tools/check_env.py +55 -14
- package/tools/check_version_sync.py +153 -0
- package/tools/ci_healing_hook.py +1 -1
- package/tools/cli.py +263 -13
- package/tools/count_tokens.py +1257 -0
- package/tools/dashboard_generator.py +2638 -0
- package/tools/db_sandbox.py +198 -20
- package/tools/e2e_flow_prober.ps1 +12 -64
- package/tools/e2e_flow_prober.py +99 -0
- package/tools/e2e_flow_prober.sh +4 -0
- package/tools/export_postman_collection.py +29 -7
- package/tools/flaky_detector.py +4 -3
- package/tools/generate_allure_report.ps1 +12 -29
- package/tools/generate_allure_report.py +77 -0
- package/tools/generate_allure_report.sh +4 -0
- package/tools/generate_jmx_plan.py +299 -68
- package/tools/generate_test_reports.ps1 +12 -134
- package/tools/generate_test_reports.py +133 -0
- package/tools/generate_test_reports.sh +4 -0
- package/tools/gherkin_suite.py +758 -0
- package/tools/git_pre_commit_guard.py +12 -6
- package/tools/goldfish_review.py +366 -0
- package/tools/heal_pr_automator.py +1 -1
- package/tools/heuristic_locator_matcher.py +170 -21
- package/tools/infer_linter.py +612 -70
- package/tools/jtl_analyzer.py +1 -1
- package/tools/lint_ai_docs.py +64 -0
- package/tools/matrix_sharder.py +1 -1
- package/tools/mcp_excel_server.ps1 +12 -250
- package/tools/mcp_excel_server.py +249 -0
- package/tools/mcp_excel_server.sh +4 -0
- package/tools/mcp_server.py +368 -144
- package/tools/md_to_xlsx.py +307 -0
- package/tools/micro_mutator.py +300 -69
- package/tools/omni_transpiler.py +2 -2
- package/tools/output_formatter.py +128 -0
- package/tools/pinpoint_failure.py +88 -88
- package/tools/project_state.py +2 -2
- package/tools/repo_map.py +1 -1
- package/tools/safety_firewall.py +197 -33
- package/tools/setup_project.py +294 -30
- package/tools/skillspector.py +8 -8
- package/tools/spec_drift_sentinel.py +439 -0
- package/tools/sync_agent_rules.py +248 -0
- package/tools/telemetry_correlator.py +45 -0
- package/tools/test_impact.py +51 -12
- package/tools/tms_sync_bridge.py +21 -5
- package/tools/universal_ir.py +3 -0
- package/tools/update_sentinel.py +87 -15
- package/tools/verify_all.ps1 +13 -0
- package/tools/verify_all.py +463 -79
- package/tools/visual_diff_canvas.py +1 -0
- package/tools/visual_som_helper.py +1 -1
- package/tools/watch_mode.py +305 -0
- package/tools/welcome_page.py +291 -0
package/tools/mcp_server.py
CHANGED
|
@@ -10,8 +10,10 @@ Communicates via standard JSON-RPC stdio.
|
|
|
10
10
|
import os
|
|
11
11
|
import sys
|
|
12
12
|
import json
|
|
13
|
+
import re
|
|
13
14
|
import traceback
|
|
14
|
-
from
|
|
15
|
+
from pathlib import Path
|
|
16
|
+
from typing import Dict, Any, List, Optional, Set
|
|
15
17
|
|
|
16
18
|
# Enforce UTF-8 stdio encoding
|
|
17
19
|
if hasattr(sys.stdout, 'reconfigure'):
|
|
@@ -41,14 +43,16 @@ import tms_sync_bridge
|
|
|
41
43
|
import db_sandbox
|
|
42
44
|
import traffic_session_converter
|
|
43
45
|
import visual_som_helper
|
|
46
|
+
import gherkin_suite
|
|
47
|
+
import api_fuzzer
|
|
44
48
|
|
|
45
49
|
SERVER_NAME = "enterprise-agent-qa"
|
|
46
|
-
SERVER_VERSION = "2.
|
|
50
|
+
SERVER_VERSION = "2.4.0"
|
|
47
51
|
|
|
48
52
|
MCP_TOOLS = [
|
|
49
53
|
{
|
|
50
54
|
"name": "verify_all_gates",
|
|
51
|
-
"description": "Validates the
|
|
55
|
+
"description": "Validates the 9 Quality Gates Definition of Done (author attribution, UTF-8, paths, Clean POM, AI docs, blacklist, security, infer linter, micro-mutator).",
|
|
52
56
|
"inputSchema": {
|
|
53
57
|
"type": "object",
|
|
54
58
|
"properties": {
|
|
@@ -72,7 +76,9 @@ MCP_TOOLS = [
|
|
|
72
76
|
"inputSchema": {
|
|
73
77
|
"type": "object",
|
|
74
78
|
"properties": {
|
|
75
|
-
"repo_path": {"type": "string", "description": "Path to target project to bootstrap."}
|
|
79
|
+
"repo_path": {"type": "string", "description": "Path to target project to bootstrap."},
|
|
80
|
+
"dry_run": {"type": "boolean", "description": "Preview setup without modifying filesystem (default: false)."},
|
|
81
|
+
"no_global": {"type": "boolean", "description": "Local-only mode: do not touch ~/.gemini (default: true)."}
|
|
76
82
|
}
|
|
77
83
|
}
|
|
78
84
|
},
|
|
@@ -95,8 +101,7 @@ MCP_TOOLS = [
|
|
|
95
101
|
"properties": {
|
|
96
102
|
"action_type": {"type": "string", "description": "Action type (e.g. click, fill, submit)."},
|
|
97
103
|
"element_text": {"type": "string", "description": "Text or label of target DOM element."},
|
|
98
|
-
"selector": {"type": "string", "description": "CSS or XPath selector of element."}
|
|
99
|
-
"force": {"type": "boolean", "description": "Force bypass firewall."}
|
|
104
|
+
"selector": {"type": "string", "description": "CSS or XPath selector of element."}
|
|
100
105
|
}
|
|
101
106
|
}
|
|
102
107
|
},
|
|
@@ -136,7 +141,7 @@ MCP_TOOLS = [
|
|
|
136
141
|
},
|
|
137
142
|
{
|
|
138
143
|
"name": "run_micro_mutation",
|
|
139
|
-
"description": "Injects
|
|
144
|
+
"description": "Injects syntactic micro-mutants (flipping operators, booleans) to verify that AI-generated test assertions are robust.",
|
|
140
145
|
"inputSchema": {
|
|
141
146
|
"type": "object",
|
|
142
147
|
"properties": {
|
|
@@ -173,7 +178,7 @@ MCP_TOOLS = [
|
|
|
173
178
|
},
|
|
174
179
|
{
|
|
175
180
|
"name": "pull_alm_story",
|
|
176
|
-
"description": "Pulls User Story and Acceptance Criteria (Given-When-Then) from Jira
|
|
181
|
+
"description": "Pulls User Story and Acceptance Criteria (Given-When-Then) from Jira REST API v3 (or mock simulation) for test generation context.",
|
|
177
182
|
"inputSchema": {
|
|
178
183
|
"type": "object",
|
|
179
184
|
"properties": {
|
|
@@ -206,7 +211,8 @@ MCP_TOOLS = [
|
|
|
206
211
|
"properties": {
|
|
207
212
|
"action": {"type": "string", "enum": ["snapshot", "restore", "audit_and_purge"], "description": "Sandbox operation to execute."},
|
|
208
213
|
"db_path": {"type": "string", "description": "Path to database file (optional for SQLite)."},
|
|
209
|
-
"snapshot_id": {"type": "string", "description": "Snapshot identifier (default: pristine_baseline)."}
|
|
214
|
+
"snapshot_id": {"type": "string", "description": "Snapshot identifier (default: pristine_baseline)."},
|
|
215
|
+
"dry_run": {"type": "boolean", "description": "For audit_and_purge: preview records to purge without deleting."}
|
|
210
216
|
},
|
|
211
217
|
"required": ["action"]
|
|
212
218
|
}
|
|
@@ -234,145 +240,363 @@ MCP_TOOLS = [
|
|
|
234
240
|
"mark_id": {"type": "integer", "description": "Specific Mark ID to click."}
|
|
235
241
|
}
|
|
236
242
|
}
|
|
243
|
+
},
|
|
244
|
+
{
|
|
245
|
+
"name": "compile_gherkin_suite",
|
|
246
|
+
"description": "Compiles Gherkin .feature files into an expanded test matrix, hub Universal IR and a proven-vs-owed coverage-gap report (0 LLM tokens).",
|
|
247
|
+
"inputSchema": {
|
|
248
|
+
"type": "object",
|
|
249
|
+
"properties": {
|
|
250
|
+
"target": {"type": "string", "description": "A .feature file or directory containing .feature files."}
|
|
251
|
+
},
|
|
252
|
+
"required": ["target"]
|
|
253
|
+
}
|
|
254
|
+
},
|
|
255
|
+
{
|
|
256
|
+
"name": "fuzz_api",
|
|
257
|
+
"description": "Autonomous API fuzzing (active, dry-run by default for safety) or offline passive spec audit with ZAP-style severity taxonomy.",
|
|
258
|
+
"inputSchema": {
|
|
259
|
+
"type": "object",
|
|
260
|
+
"properties": {
|
|
261
|
+
"base_url": {"type": "string", "description": "Base URL of target API (non-production allowlist enforced)."},
|
|
262
|
+
"spec_path": {"type": "string", "description": "Path or URL to OpenAPI/Swagger JSON spec."},
|
|
263
|
+
"mode": {"type": "string", "enum": ["active", "passive"], "description": "active fuzzing or passive offline spec audit."},
|
|
264
|
+
"dry_run": {"type": "boolean", "description": "Deterministic offline mock (default true for safety)."}
|
|
265
|
+
},
|
|
266
|
+
"required": ["base_url"]
|
|
267
|
+
}
|
|
237
268
|
}
|
|
238
269
|
]
|
|
239
270
|
|
|
240
271
|
|
|
272
|
+
def _validate_safe_path(filepath: str, allowed_root: Optional[str] = None, allowed_exts: Optional[Set[str]] = None) -> str:
|
|
273
|
+
"""
|
|
274
|
+
Validates that a path is safe and does not access restricted system paths or traverse outside the project root.
|
|
275
|
+
Resolves symlinks via Path.resolve() and enforces cross-platform boundaries (Windows, macOS, Linux).
|
|
276
|
+
"""
|
|
277
|
+
if not filepath or not isinstance(filepath, str):
|
|
278
|
+
raise ValueError("File path must be a non-empty string")
|
|
279
|
+
|
|
280
|
+
# Reject null bytes and Windows UNC network share paths
|
|
281
|
+
if "\0" in filepath or filepath.startswith("\\\\"):
|
|
282
|
+
raise PermissionError(f"Access denied: invalid or UNC path '{filepath}'")
|
|
283
|
+
|
|
284
|
+
effective_root = allowed_root or os.environ.get("SYNAPSE_PROJECT_ROOT") or os.getcwd()
|
|
285
|
+
try:
|
|
286
|
+
root_path = Path(effective_root).resolve()
|
|
287
|
+
target_path = Path(filepath).resolve()
|
|
288
|
+
except Exception as e:
|
|
289
|
+
raise PermissionError(f"Access denied: cannot resolve path '{filepath}': {e}")
|
|
290
|
+
|
|
291
|
+
# Case-insensitive path comparison across OS filesystems
|
|
292
|
+
root_norm = os.path.normcase(str(root_path))
|
|
293
|
+
target_norm = os.path.normcase(str(target_path))
|
|
294
|
+
|
|
295
|
+
# Path must reside within the allowed root
|
|
296
|
+
if target_norm != root_norm and not target_norm.startswith(root_norm + os.sep):
|
|
297
|
+
raise PermissionError(f"Access denied: path '{filepath}' resolves outside allowed project root '{root_path}'")
|
|
298
|
+
|
|
299
|
+
# Reject explicit sensitive configuration / secret files
|
|
300
|
+
base_name = target_path.name.lower()
|
|
301
|
+
if base_name in {".env", ".env.local", ".env.production", ".env.staging", ".npmrc", ".netrc", ".git-credentials"}:
|
|
302
|
+
raise PermissionError(f"Access denied: path references sensitive configuration file '{target_path.name}'")
|
|
303
|
+
|
|
304
|
+
# Cross-platform sensitive system prefixes
|
|
305
|
+
try:
|
|
306
|
+
user_home = Path.home().resolve()
|
|
307
|
+
except Exception:
|
|
308
|
+
user_home = Path(os.path.expanduser("~")).resolve()
|
|
309
|
+
|
|
310
|
+
sensitive_prefixes = [
|
|
311
|
+
Path("/etc"), Path("/var/run"), Path("/proc"), Path("/sys"), Path("/dev"), Path("/root"), Path("/private/etc"),
|
|
312
|
+
user_home / ".ssh",
|
|
313
|
+
user_home / ".aws",
|
|
314
|
+
user_home / ".gnupg",
|
|
315
|
+
user_home / ".kube",
|
|
316
|
+
user_home / ".docker",
|
|
317
|
+
user_home / ".config" / "gh",
|
|
318
|
+
user_home / "Library" / "Keychains",
|
|
319
|
+
]
|
|
320
|
+
if sys.platform == "win32":
|
|
321
|
+
for env_win in ("SystemRoot", "WINDIR", "APPDATA", "LOCALAPPDATA", "ProgramFiles", "ProgramFiles(x86)"):
|
|
322
|
+
win_val = os.environ.get(env_win)
|
|
323
|
+
if win_val:
|
|
324
|
+
try:
|
|
325
|
+
sensitive_prefixes.append(Path(win_val).resolve())
|
|
326
|
+
except Exception:
|
|
327
|
+
pass
|
|
328
|
+
|
|
329
|
+
for sp in sensitive_prefixes:
|
|
330
|
+
sp_norm = os.path.normcase(str(sp))
|
|
331
|
+
if target_norm == sp_norm or target_norm.startswith(sp_norm + os.sep):
|
|
332
|
+
raise PermissionError(f"Access denied: path references restricted system directory '{sp}'")
|
|
333
|
+
|
|
334
|
+
if allowed_exts:
|
|
335
|
+
ext = target_path.suffix.lower()
|
|
336
|
+
if ext not in allowed_exts and not target_path.is_dir():
|
|
337
|
+
raise PermissionError(f"Access denied: file extension '{ext}' is not permitted")
|
|
338
|
+
|
|
339
|
+
return str(target_path)
|
|
340
|
+
|
|
341
|
+
|
|
342
|
+
def _handle_verify_all_gates(arguments: Dict[str, Any]) -> str:
|
|
343
|
+
repo = _validate_safe_path(arguments.get("repo_path") or os.getcwd())
|
|
344
|
+
mode = verify_all.detect_repo_mode(repo)
|
|
345
|
+
passed = True
|
|
346
|
+
gates = [
|
|
347
|
+
("Gate 0: Author Integrity", verify_all.gate_0_author_integrity),
|
|
348
|
+
("Gate 1: UTF-8 No BOM", verify_all.gate_1_bom_check),
|
|
349
|
+
("Gate 2: Path Portability", verify_all.gate_2_path_portability),
|
|
350
|
+
("Gate 3: Clean POM", verify_all.gate_3_clean_pom),
|
|
351
|
+
("Gate 4: AI Docs Linter", verify_all.gate_4_ai_docs_lint),
|
|
352
|
+
("Gate 5: Temp Blacklist", verify_all.gate_5_cleanup_blacklist),
|
|
353
|
+
("Gate 6: Credential Security", verify_all.gate_6_credential_security),
|
|
354
|
+
("Gate 7: Infer Linter", verify_all.gate_7_infer_linter),
|
|
355
|
+
("Gate 8: AST Mutation Sentinel", verify_all.gate_8_micro_mutator),
|
|
356
|
+
]
|
|
357
|
+
results = []
|
|
358
|
+
for g_name, g_fn in gates:
|
|
359
|
+
res = g_fn(repo, mode=mode)
|
|
360
|
+
results.append(f"{g_name}: {'PASS' if res else 'FAIL'}")
|
|
361
|
+
if not res:
|
|
362
|
+
passed = False
|
|
363
|
+
summary = "100% ALL 9 GATES PASSED" if passed else "VERIFICATION FAILED"
|
|
364
|
+
return f"[{summary}]\n" + "\n".join(results)
|
|
365
|
+
|
|
366
|
+
|
|
367
|
+
def _handle_analyze_project(arguments: Dict[str, Any]) -> str:
|
|
368
|
+
repo = _validate_safe_path(arguments.get("repo_path") or os.getcwd())
|
|
369
|
+
code = analyze_project.run_full_analysis(repo)
|
|
370
|
+
return f"Project Analysis finished with exit code {code}. Report saved at {os.path.join(repo, 'PROJECT_HEALTH_REPORT.md')}."
|
|
371
|
+
|
|
372
|
+
|
|
373
|
+
def _handle_setup_project(arguments: Dict[str, Any]) -> str:
|
|
374
|
+
repo = _validate_safe_path(arguments.get("repo_path") or os.getcwd())
|
|
375
|
+
dry_run = bool(arguments.get("dry_run", False))
|
|
376
|
+
no_global = bool(arguments.get("no_global", True))
|
|
377
|
+
code = setup_project.run_setup(
|
|
378
|
+
repo,
|
|
379
|
+
dry_run=dry_run,
|
|
380
|
+
no_global=no_global,
|
|
381
|
+
no_git_hook=True,
|
|
382
|
+
no_browser=True,
|
|
383
|
+
open_browser=False
|
|
384
|
+
)
|
|
385
|
+
mode_label = " (DRY-RUN)" if dry_run else ""
|
|
386
|
+
return f"Project Setup finished with exit code {code}{mode_label}."
|
|
387
|
+
|
|
388
|
+
|
|
389
|
+
def _handle_auto_heal_failure(arguments: Dict[str, Any]) -> str:
|
|
390
|
+
target = _validate_safe_path(arguments.get("target_dir") or os.getcwd())
|
|
391
|
+
xml = _validate_safe_path(arguments["junit_xml_path"]) if arguments.get("junit_xml_path") else None
|
|
392
|
+
plan = auto_heal.diagnose_and_plan_heal(target, xml)
|
|
393
|
+
return json.dumps(plan, indent=2)
|
|
394
|
+
|
|
395
|
+
|
|
396
|
+
def _handle_check_action_safety(arguments: Dict[str, Any]) -> str:
|
|
397
|
+
auth = safety_firewall.inspect_and_authorize(
|
|
398
|
+
action_type=arguments.get("action_type", "click"),
|
|
399
|
+
text=arguments.get("element_text", ""),
|
|
400
|
+
selector=arguments.get("selector", ""),
|
|
401
|
+
force=False
|
|
402
|
+
)
|
|
403
|
+
return json.dumps(auth, indent=2)
|
|
404
|
+
|
|
405
|
+
|
|
406
|
+
def _handle_check_contract_drift(arguments: Dict[str, Any]) -> str:
|
|
407
|
+
old_path = _validate_safe_path(arguments["old_spec_path"])
|
|
408
|
+
new_path = _validate_safe_path(arguments["new_spec_path"])
|
|
409
|
+
old_data = api_drift_sentinel.load_spec(old_path)
|
|
410
|
+
new_data = api_drift_sentinel.load_spec(new_path)
|
|
411
|
+
analysis = api_drift_sentinel.compare_specs(old_data, new_data)
|
|
412
|
+
return api_drift_sentinel.generate_markdown_report(analysis, old_path, new_path)
|
|
413
|
+
|
|
414
|
+
|
|
415
|
+
def _handle_query_memory_cache(arguments: Dict[str, Any]) -> str:
|
|
416
|
+
res = cache_resolver.query_solution(arguments["error_signature"])
|
|
417
|
+
return json.dumps(res, indent=2) if res else "No matching solution found in memory cache."
|
|
418
|
+
|
|
419
|
+
|
|
420
|
+
def _handle_distill_log(arguments: Dict[str, Any]) -> str:
|
|
421
|
+
return distill_log.distill_log_content(arguments["raw_log_text"])
|
|
422
|
+
|
|
423
|
+
|
|
424
|
+
def _handle_run_micro_mutation(arguments: Dict[str, Any]) -> str:
|
|
425
|
+
target = _validate_safe_path(
|
|
426
|
+
arguments.get("target_path") or os.getcwd(),
|
|
427
|
+
allowed_exts={".py", ".ts", ".js", ".groovy", ".java"}
|
|
428
|
+
)
|
|
429
|
+
if os.path.isdir(target):
|
|
430
|
+
mutants = micro_mutator.scan_directory_for_mutants(target)
|
|
431
|
+
else:
|
|
432
|
+
with open(target, "r", encoding="utf-8", errors="ignore") as f:
|
|
433
|
+
content = f.read()
|
|
434
|
+
mutants = micro_mutator.generate_mutants_for_code(content, target)
|
|
435
|
+
|
|
436
|
+
sanitized_samples = []
|
|
437
|
+
for m in mutants[:5]:
|
|
438
|
+
sanitized_samples.append({
|
|
439
|
+
"id": m.get("id"),
|
|
440
|
+
"file": m.get("file"),
|
|
441
|
+
"line": m.get("line"),
|
|
442
|
+
"operator": m.get("description", "mutation"),
|
|
443
|
+
"original_snippet": m.get("original_snippet", ""),
|
|
444
|
+
"mutated_snippet": m.get("mutated_snippet", ""),
|
|
445
|
+
"status": m.get("status", "PENDING")
|
|
446
|
+
})
|
|
447
|
+
return json.dumps({"total_mutants": len(mutants), "sample_mutants": sanitized_samples}, indent=2)
|
|
448
|
+
|
|
449
|
+
|
|
450
|
+
def _handle_plan_healing_pr(arguments: Dict[str, Any]) -> str:
|
|
451
|
+
page_file = _validate_safe_path(arguments["page_file"])
|
|
452
|
+
conf = heal_pr_automator.calculate_healing_confidence(
|
|
453
|
+
arguments.get("aom_score", 0.95),
|
|
454
|
+
arguments.get("spatial_score", 0.90),
|
|
455
|
+
arguments.get("visual_score", 0.92)
|
|
456
|
+
)
|
|
457
|
+
pr = heal_pr_automator.generate_pr_draft(page_file, arguments["old_locator"], arguments["new_locator"], conf)
|
|
458
|
+
return json.dumps({"confidence": conf, "pr": pr}, indent=2)
|
|
459
|
+
|
|
460
|
+
|
|
461
|
+
def _handle_shard_test_matrix(arguments: Dict[str, Any]) -> str:
|
|
462
|
+
target = _validate_safe_path(arguments.get("target_dir") or os.getcwd())
|
|
463
|
+
num_shards = arguments.get("num_shards", 4)
|
|
464
|
+
files = matrix_sharder.find_test_files(target)
|
|
465
|
+
shards = matrix_sharder.shard_tests_lpt(files, target, num_shards)
|
|
466
|
+
return json.dumps({"total_tests": len(files), "shards": shards}, indent=2)
|
|
467
|
+
|
|
468
|
+
|
|
469
|
+
def _handle_pull_alm_story(arguments: Dict[str, Any]) -> str:
|
|
470
|
+
bridge = tms_sync_bridge.TMSBridge()
|
|
471
|
+
story = bridge.pull_story_acceptance_criteria(arguments["issue_key"])
|
|
472
|
+
return json.dumps(story, indent=2)
|
|
473
|
+
|
|
474
|
+
|
|
475
|
+
def _handle_report_alm_defect(arguments: Dict[str, Any]) -> str:
|
|
476
|
+
bridge = tms_sync_bridge.TMSBridge()
|
|
477
|
+
ticket = bridge.report_defect(
|
|
478
|
+
project_key=arguments["project_key"],
|
|
479
|
+
test_case_id=arguments["test_case_id"],
|
|
480
|
+
summary=arguments["summary"],
|
|
481
|
+
error_message=arguments["error_message"],
|
|
482
|
+
stack_trace=arguments.get("stack_trace", ""),
|
|
483
|
+
screenshot_path=arguments.get("screenshot_path", "")
|
|
484
|
+
)
|
|
485
|
+
return json.dumps(ticket, indent=2)
|
|
486
|
+
|
|
487
|
+
|
|
488
|
+
def _handle_manage_db_sandbox(arguments: Dict[str, Any]) -> str:
|
|
489
|
+
action = arguments["action"]
|
|
490
|
+
raw_db = arguments.get("db_path", "")
|
|
491
|
+
safe_db = _validate_safe_path(raw_db) if raw_db else ""
|
|
492
|
+
raw_id = arguments.get("snapshot_id", "pristine_baseline")
|
|
493
|
+
safe_id = re.sub(r'[^a-zA-Z0-9_\-]', '', raw_id) or "pristine_baseline"
|
|
494
|
+
|
|
495
|
+
sandbox = db_sandbox.DBSandbox(db_path=safe_db)
|
|
496
|
+
if action == "snapshot":
|
|
497
|
+
res = sandbox.create_snapshot(safe_id)
|
|
498
|
+
elif action == "restore":
|
|
499
|
+
res = sandbox.restore_snapshot(safe_id)
|
|
500
|
+
elif action == "audit_and_purge":
|
|
501
|
+
dry_run = bool(arguments.get("dry_run", False))
|
|
502
|
+
res = sandbox.audit_and_purge_pollution(dry_run=dry_run)
|
|
503
|
+
else:
|
|
504
|
+
raise ValueError(f"Unknown sandbox action: {action}")
|
|
505
|
+
return json.dumps(res, indent=2)
|
|
506
|
+
|
|
507
|
+
|
|
508
|
+
def _handle_convert_traffic_session(arguments: Dict[str, Any]) -> str:
|
|
509
|
+
input_file = _validate_safe_path(arguments["input_file"])
|
|
510
|
+
test_name = arguments.get("test_name", "ProductionTrafficReplay")
|
|
511
|
+
with open(input_file, "r", encoding="utf-8", errors="ignore") as f:
|
|
512
|
+
data = json.load(f)
|
|
513
|
+
converter = traffic_session_converter.TrafficConverter(sanitize_pii=True)
|
|
514
|
+
requests = converter.parse_har(data)
|
|
515
|
+
test_code = converter.generate_playwright_test(requests, test_name=test_name)
|
|
516
|
+
return json.dumps({"total_requests": len(requests), "generated_test": test_code}, indent=2)
|
|
517
|
+
|
|
518
|
+
|
|
519
|
+
def _handle_resolve_visual_som_coordinates(arguments: Dict[str, Any]) -> str:
|
|
520
|
+
helper = visual_som_helper.VisualSoMHelper()
|
|
521
|
+
img = arguments.get("image_path", "screenshot.png")
|
|
522
|
+
lbl = arguments.get("target_label")
|
|
523
|
+
mid = arguments.get("mark_id")
|
|
524
|
+
marked_img, marks_map = helper.generate_som_overlay(img, [])
|
|
525
|
+
resolved = helper.resolve_mark_coordinates(marks_map, target_mark_id=mid, target_label=lbl)
|
|
526
|
+
return json.dumps({"marked_image": marked_img, "resolved_target": resolved}, indent=2)
|
|
527
|
+
|
|
528
|
+
|
|
529
|
+
def _handle_compile_gherkin_suite(arguments: Dict[str, Any]) -> str:
|
|
530
|
+
target = arguments["target"]
|
|
531
|
+
res = gherkin_suite.compile_feature(target) if os.path.isfile(target) else gherkin_suite.run(target)
|
|
532
|
+
if isinstance(res, int):
|
|
533
|
+
return json.dumps({"exit_code": res, "detail": "see reports/gherkin_suite_report.json"}, indent=2)
|
|
534
|
+
persist = {k: v for k, v in res.items() if not k.startswith("_")}
|
|
535
|
+
return json.dumps({
|
|
536
|
+
"feature": persist.get("feature"),
|
|
537
|
+
"totals": persist.get("totals"),
|
|
538
|
+
"errors": persist.get("errors"),
|
|
539
|
+
"gaps": persist.get("gaps"),
|
|
540
|
+
"health_score_pct": persist.get("health_score_pct"),
|
|
541
|
+
}, indent=2)
|
|
542
|
+
|
|
543
|
+
|
|
544
|
+
def _handle_fuzz_api(arguments: Dict[str, Any]) -> str:
|
|
545
|
+
mode = arguments.get("mode", "active")
|
|
546
|
+
dry_run = arguments.get("dry_run", True)
|
|
547
|
+
spec_path = arguments.get("spec_path")
|
|
548
|
+
if spec_path and not (spec_path.startswith("http://") or spec_path.startswith("https://")):
|
|
549
|
+
spec_path = _validate_safe_path(spec_path)
|
|
550
|
+
fuzzer = api_fuzzer.ApiFuzzer(
|
|
551
|
+
base_url=arguments["base_url"],
|
|
552
|
+
spec_path_or_url=spec_path,
|
|
553
|
+
)
|
|
554
|
+
if mode == "passive":
|
|
555
|
+
scorecard = fuzzer.run_passive_scan()
|
|
556
|
+
return json.dumps({
|
|
557
|
+
"mode": scorecard["mode"],
|
|
558
|
+
"total_findings": scorecard["total_findings"],
|
|
559
|
+
"severity_summary": scorecard["severity_summary"],
|
|
560
|
+
"findings": scorecard["findings"],
|
|
561
|
+
}, indent=2)
|
|
562
|
+
scorecard = fuzzer.run_fuzz_suite(dry_run=dry_run)
|
|
563
|
+
return json.dumps({
|
|
564
|
+
"mode": scorecard["mode"],
|
|
565
|
+
"total_mutations": scorecard["total_mutations"],
|
|
566
|
+
"passed": scorecard["passed"],
|
|
567
|
+
"failed": scorecard["failed"],
|
|
568
|
+
"severity_summary": scorecard["severity_summary"],
|
|
569
|
+
}, indent=2)
|
|
570
|
+
|
|
571
|
+
|
|
572
|
+
TOOL_DISPATCH_TABLE: Dict[str, Any] = {
|
|
573
|
+
"verify_all_gates": _handle_verify_all_gates,
|
|
574
|
+
"analyze_project": _handle_analyze_project,
|
|
575
|
+
"setup_project": _handle_setup_project,
|
|
576
|
+
"auto_heal_failure": _handle_auto_heal_failure,
|
|
577
|
+
"check_action_safety": _handle_check_action_safety,
|
|
578
|
+
"check_contract_drift": _handle_check_contract_drift,
|
|
579
|
+
"query_memory_cache": _handle_query_memory_cache,
|
|
580
|
+
"distill_log": _handle_distill_log,
|
|
581
|
+
"run_micro_mutation": _handle_run_micro_mutation,
|
|
582
|
+
"plan_healing_pr": _handle_plan_healing_pr,
|
|
583
|
+
"shard_test_matrix": _handle_shard_test_matrix,
|
|
584
|
+
"pull_alm_story": _handle_pull_alm_story,
|
|
585
|
+
"report_alm_defect": _handle_report_alm_defect,
|
|
586
|
+
"manage_db_sandbox": _handle_manage_db_sandbox,
|
|
587
|
+
"convert_traffic_session": _handle_convert_traffic_session,
|
|
588
|
+
"resolve_visual_som_coordinates": _handle_resolve_visual_som_coordinates,
|
|
589
|
+
"compile_gherkin_suite": _handle_compile_gherkin_suite,
|
|
590
|
+
"fuzz_api": _handle_fuzz_api,
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
|
|
241
594
|
def handle_tool_call(name: str, arguments: Dict[str, Any]) -> str:
|
|
242
|
-
"""Executes the corresponding internal tool function
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
gates = [
|
|
248
|
-
("Gate 1: UTF-8 No BOM", verify_all.gate_1_bom_check),
|
|
249
|
-
("Gate 2: Path Portability", verify_all.gate_2_path_portability),
|
|
250
|
-
("Gate 3: Clean POM", verify_all.gate_3_clean_pom),
|
|
251
|
-
("Gate 4: AI Docs Linter", verify_all.gate_4_ai_docs_lint),
|
|
252
|
-
("Gate 5: Temp Blacklist", verify_all.gate_5_cleanup_blacklist),
|
|
253
|
-
("Gate 6: Credential Security", verify_all.gate_6_credential_security),
|
|
254
|
-
("Gate 7: Infer Linter", verify_all.gate_7_infer_linter),
|
|
255
|
-
("Gate 8: AST Mutation Sentinel", verify_all.gate_8_micro_mutator),
|
|
256
|
-
]
|
|
257
|
-
results = []
|
|
258
|
-
for g_name, g_fn in gates:
|
|
259
|
-
res = g_fn(repo, mode=mode)
|
|
260
|
-
results.append(f"{g_name}: {'PASS' if res else 'FAIL'}")
|
|
261
|
-
if not res:
|
|
262
|
-
passed = False
|
|
263
|
-
summary = "100% ALL 8 GATES PASSED" if passed else "VERIFICATION FAILED"
|
|
264
|
-
return f"[{summary}]\n" + "\n".join(results)
|
|
265
|
-
|
|
266
|
-
elif name == "analyze_project":
|
|
267
|
-
repo = arguments.get("repo_path") or os.getcwd()
|
|
268
|
-
code = analyze_project.run_full_analysis(repo)
|
|
269
|
-
return f"Project Analysis finished with exit code {code}. Report saved at {os.path.join(repo, 'PROJECT_HEALTH_REPORT.md')}."
|
|
270
|
-
|
|
271
|
-
elif name == "setup_project":
|
|
272
|
-
repo = arguments.get("repo_path") or os.getcwd()
|
|
273
|
-
code = setup_project.run_setup(repo)
|
|
274
|
-
return f"Project Setup finished with exit code {code}."
|
|
275
|
-
|
|
276
|
-
elif name == "auto_heal_failure":
|
|
277
|
-
target = arguments.get("target_dir") or os.getcwd()
|
|
278
|
-
xml = arguments.get("junit_xml_path")
|
|
279
|
-
plan = auto_heal.diagnose_and_plan_heal(target, xml)
|
|
280
|
-
return json.dumps(plan, indent=2)
|
|
281
|
-
|
|
282
|
-
elif name == "check_action_safety":
|
|
283
|
-
auth = safety_firewall.inspect_and_authorize(
|
|
284
|
-
action_type=arguments.get("action_type", "click"),
|
|
285
|
-
text=arguments.get("element_text", ""),
|
|
286
|
-
selector=arguments.get("selector", ""),
|
|
287
|
-
force=arguments.get("force", False)
|
|
288
|
-
)
|
|
289
|
-
return json.dumps(auth, indent=2)
|
|
290
|
-
|
|
291
|
-
elif name == "check_contract_drift":
|
|
292
|
-
old_data = api_drift_sentinel.load_spec(arguments["old_spec_path"])
|
|
293
|
-
new_data = api_drift_sentinel.load_spec(arguments["new_spec_path"])
|
|
294
|
-
analysis = api_drift_sentinel.compare_specs(old_data, new_data)
|
|
295
|
-
return api_drift_sentinel.generate_markdown_report(analysis, arguments["old_spec_path"], arguments["new_spec_path"])
|
|
296
|
-
|
|
297
|
-
elif name == "query_memory_cache":
|
|
298
|
-
res = cache_resolver.query_cache(arguments["error_signature"])
|
|
299
|
-
return json.dumps(res, indent=2) if res else "No matching solution found in memory cache."
|
|
300
|
-
|
|
301
|
-
elif name == "distill_log":
|
|
302
|
-
distilled = distill_log.distill_log_content(arguments["raw_log_text"])
|
|
303
|
-
return distilled
|
|
304
|
-
|
|
305
|
-
elif name == "run_micro_mutation":
|
|
306
|
-
target = arguments.get("target_path") or os.getcwd()
|
|
307
|
-
mutants = micro_mutator.scan_directory_for_mutants(target) if os.path.isdir(target) else micro_mutator.generate_mutants_for_code(open(target).read(), target)
|
|
308
|
-
return json.dumps({"total_mutants": len(mutants), "sample_mutants": mutants[:5]}, indent=2)
|
|
309
|
-
|
|
310
|
-
elif name == "plan_healing_pr":
|
|
311
|
-
conf = heal_pr_automator.calculate_healing_confidence(
|
|
312
|
-
arguments.get("aom_score", 0.95),
|
|
313
|
-
arguments.get("spatial_score", 0.90),
|
|
314
|
-
arguments.get("visual_score", 0.92)
|
|
315
|
-
)
|
|
316
|
-
pr = heal_pr_automator.generate_pr_draft(arguments["page_file"], arguments["old_locator"], arguments["new_locator"], conf)
|
|
317
|
-
return json.dumps({"confidence": conf, "pr": pr}, indent=2)
|
|
318
|
-
|
|
319
|
-
elif name == "shard_test_matrix":
|
|
320
|
-
target = arguments.get("target_dir") or os.getcwd()
|
|
321
|
-
num_shards = arguments.get("num_shards", 4)
|
|
322
|
-
files = matrix_sharder.find_test_files(target)
|
|
323
|
-
shards = matrix_sharder.shard_tests_lpt(files, target, num_shards)
|
|
324
|
-
return json.dumps({"total_tests": len(files), "shards": shards}, indent=2)
|
|
325
|
-
|
|
326
|
-
elif name == "pull_alm_story":
|
|
327
|
-
bridge = tms_sync_bridge.TMSBridge()
|
|
328
|
-
story = bridge.pull_story_acceptance_criteria(arguments["issue_key"])
|
|
329
|
-
return json.dumps(story, indent=2)
|
|
330
|
-
|
|
331
|
-
elif name == "report_alm_defect":
|
|
332
|
-
bridge = tms_sync_bridge.TMSBridge()
|
|
333
|
-
ticket = bridge.report_defect(
|
|
334
|
-
project_key=arguments["project_key"],
|
|
335
|
-
test_case_id=arguments["test_case_id"],
|
|
336
|
-
summary=arguments["summary"],
|
|
337
|
-
error_message=arguments["error_message"],
|
|
338
|
-
stack_trace=arguments.get("stack_trace", ""),
|
|
339
|
-
screenshot_path=arguments.get("screenshot_path", "")
|
|
340
|
-
)
|
|
341
|
-
return json.dumps(ticket, indent=2)
|
|
342
|
-
|
|
343
|
-
elif name == "manage_db_sandbox":
|
|
344
|
-
action = arguments["action"]
|
|
345
|
-
sandbox = db_sandbox.DBSandbox(db_path=arguments.get("db_path", ""))
|
|
346
|
-
if action == "snapshot":
|
|
347
|
-
res = sandbox.create_snapshot(arguments.get("snapshot_id", "pristine_baseline"))
|
|
348
|
-
elif action == "restore":
|
|
349
|
-
res = sandbox.restore_snapshot(arguments.get("snapshot_id", "pristine_baseline"))
|
|
350
|
-
elif action == "audit_and_purge":
|
|
351
|
-
res = sandbox.audit_and_purge_pollution()
|
|
352
|
-
else:
|
|
353
|
-
raise ValueError(f"Unknown sandbox action: {action}")
|
|
354
|
-
return json.dumps(res, indent=2)
|
|
355
|
-
|
|
356
|
-
elif name == "convert_traffic_session":
|
|
357
|
-
input_file = arguments["input_file"]
|
|
358
|
-
test_name = arguments.get("test_name", "ProductionTrafficReplay")
|
|
359
|
-
with open(input_file, "r", encoding="utf-8", errors="ignore") as f:
|
|
360
|
-
data = json.load(f)
|
|
361
|
-
converter = traffic_session_converter.TrafficConverter(sanitize_pii=True)
|
|
362
|
-
requests = converter.parse_har(data)
|
|
363
|
-
test_code = converter.generate_playwright_test(requests, test_name=test_name)
|
|
364
|
-
return json.dumps({"total_requests": len(requests), "generated_test": test_code}, indent=2)
|
|
365
|
-
|
|
366
|
-
elif name == "resolve_visual_som_coordinates":
|
|
367
|
-
helper = visual_som_helper.VisualSoMHelper()
|
|
368
|
-
img = arguments.get("image_path", "screenshot.png")
|
|
369
|
-
lbl = arguments.get("target_label")
|
|
370
|
-
mid = arguments.get("mark_id")
|
|
371
|
-
marked_img, marks_map = helper.generate_som_overlay(img, [])
|
|
372
|
-
resolved = helper.resolve_mark_coordinates(marks_map, target_mark_id=mid, target_label=lbl)
|
|
373
|
-
return json.dumps({"marked_image": marked_img, "resolved_target": resolved}, indent=2)
|
|
374
|
-
|
|
375
|
-
raise ValueError(f"Unknown MCP tool: {name}")
|
|
595
|
+
"""Executes the corresponding internal tool function via dispatch table."""
|
|
596
|
+
handler = TOOL_DISPATCH_TABLE.get(name)
|
|
597
|
+
if not handler:
|
|
598
|
+
raise ValueError(f"Unknown MCP tool: {name}")
|
|
599
|
+
return handler(arguments)
|
|
376
600
|
|
|
377
601
|
|
|
378
602
|
def process_message(msg: Dict[str, Any]) -> Dict[str, Any]:
|
|
@@ -435,7 +659,7 @@ def process_message(msg: Dict[str, Any]) -> Dict[str, Any]:
|
|
|
435
659
|
"content": [
|
|
436
660
|
{
|
|
437
661
|
"type": "text",
|
|
438
|
-
"text": f"Error executing {tool_name}: {
|
|
662
|
+
"text": f"Error executing {tool_name}: {type(e).__name__}: {str(e)}"
|
|
439
663
|
}
|
|
440
664
|
],
|
|
441
665
|
"isError": True
|