synapse-hub 2.2.4 → 2.4.1
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 +23 -4
- package/.agents/agents/pom-crafter.md +15 -0
- package/.agents/agents/quality-gatekeeper.md +20 -4
- package/.agents/agents/test-runner.md +12 -0
- package/.agents/rules/communication-style.md +40 -0
- package/.agents/rules/context-engineering.md +23 -0
- package/.agents/rules/git-push-protocol.md +10 -16
- package/.agents/rules/graphify.md +14 -14
- 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/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 +1 -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/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 +54 -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 +331 -0
- package/README.md +252 -515
- 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 +16 -4
- 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 +27 -12
- 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 +98 -131
- 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 +30 -3
- package/tools/cache_resolver.py +248 -14
- package/tools/check_env.py +55 -14
- package/tools/check_version_sync.py +171 -0
- package/tools/ci_healing_hook.py +1 -1
- package/tools/cli.py +454 -42
- 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/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 +257 -58
- 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/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 +302 -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 +196 -45
- package/tools/setup_project.py +295 -31
- package/tools/skillspector.py +31 -0
- 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 +479 -85
- 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/cli.py
CHANGED
|
@@ -12,6 +12,9 @@ Dispatches commands to underlying specialized tools in tools/.
|
|
|
12
12
|
|
|
13
13
|
import os
|
|
14
14
|
import sys
|
|
15
|
+
import json
|
|
16
|
+
import re
|
|
17
|
+
import difflib
|
|
15
18
|
import argparse
|
|
16
19
|
|
|
17
20
|
# Enforce UTF-8 stdout encoding for Windows console compatibility
|
|
@@ -26,26 +29,35 @@ SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
|
|
|
26
29
|
REPO_ROOT = os.path.abspath(os.path.join(SCRIPT_DIR, ".."))
|
|
27
30
|
sys.path.insert(0, SCRIPT_DIR)
|
|
28
31
|
|
|
32
|
+
# ANSI Color formatting
|
|
33
|
+
CYAN = "\033[96m"
|
|
34
|
+
GREEN = "\033[92m"
|
|
35
|
+
YELLOW = "\033[93m"
|
|
36
|
+
RED = "\033[91m"
|
|
37
|
+
BOLD = "\033[1m"
|
|
38
|
+
RESET = "\033[0m"
|
|
39
|
+
|
|
29
40
|
|
|
30
41
|
def cmd_version(args):
|
|
42
|
+
"""Displays the current hub version, skill catalog count, and license information."""
|
|
31
43
|
manifest_path = os.path.join(REPO_ROOT, "skills_manifest.json")
|
|
32
|
-
version = "2.
|
|
44
|
+
version = "2.4.1"
|
|
33
45
|
if os.path.exists(manifest_path):
|
|
34
46
|
try:
|
|
35
47
|
import json
|
|
36
48
|
with open(manifest_path, "r", encoding="utf-8") as f:
|
|
37
49
|
data = json.load(f)
|
|
38
50
|
version = data.get("version", version)
|
|
39
|
-
except
|
|
51
|
+
except (OSError, json.JSONDecodeError):
|
|
40
52
|
pass
|
|
41
53
|
print(f"Agent-QA Hub CLI v{version}")
|
|
42
|
-
manifest_skills =
|
|
54
|
+
manifest_skills = 38
|
|
43
55
|
if os.path.exists(manifest_path):
|
|
44
56
|
try:
|
|
45
57
|
import json
|
|
46
58
|
with open(manifest_path, "r", encoding="utf-8") as f:
|
|
47
|
-
manifest_skills = json.load(f).get("totalSkills",
|
|
48
|
-
except
|
|
59
|
+
manifest_skills = json.load(f).get("totalSkills", 38)
|
|
60
|
+
except (OSError, json.JSONDecodeError):
|
|
49
61
|
pass
|
|
50
62
|
print(f"Catalog: {manifest_skills} Standardized Skills | 6 Subagent Swarm Profiles")
|
|
51
63
|
print("Created by: Thế Vị (@TeeVee998) <https://github.com/TeeVee998/Synapse-Hub>")
|
|
@@ -53,6 +65,7 @@ def cmd_version(args):
|
|
|
53
65
|
|
|
54
66
|
|
|
55
67
|
def cmd_verify_author(args):
|
|
68
|
+
"""Validates author attribution and MIT provenance integrity across the repository."""
|
|
56
69
|
from author_integrity import verify_author_attribution, get_canonical_watermark, enforce_author_attribution
|
|
57
70
|
valid, violations = verify_author_attribution()
|
|
58
71
|
if valid:
|
|
@@ -62,33 +75,52 @@ def cmd_verify_author(args):
|
|
|
62
75
|
enforce_author_attribution(strict=True)
|
|
63
76
|
|
|
64
77
|
|
|
78
|
+
def _forward_subcommand_args(args_or_name=None) -> list:
|
|
79
|
+
"""Safely extracts and forwards arguments intended for the underlying subcommand tool."""
|
|
80
|
+
subcmd = None
|
|
81
|
+
if isinstance(args_or_name, str):
|
|
82
|
+
subcmd = args_or_name
|
|
83
|
+
elif hasattr(args_or_name, "subcommand"):
|
|
84
|
+
subcmd = args_or_name.subcommand
|
|
85
|
+
|
|
86
|
+
if subcmd and subcmd in sys.argv:
|
|
87
|
+
idx = sys.argv.index(subcmd)
|
|
88
|
+
return [sys.argv[0]] + sys.argv[idx + 1:]
|
|
89
|
+
return [sys.argv[0]] + (sys.argv[2:] if len(sys.argv) > 2 else [])
|
|
90
|
+
|
|
91
|
+
|
|
65
92
|
def cmd_verify(args):
|
|
93
|
+
"""Executes the 9 Quality Gates Definition of Done (DoD) verification suite."""
|
|
66
94
|
from verify_all import main as verify_main
|
|
67
|
-
sys.argv =
|
|
95
|
+
sys.argv = _forward_subcommand_args(args)
|
|
68
96
|
sys.exit(verify_main())
|
|
69
97
|
|
|
70
98
|
|
|
71
99
|
def cmd_lint(args):
|
|
100
|
+
"""Runs the Meta Infer-style AST Fake-Pass, zero-assertion, and hard sleep scanner."""
|
|
72
101
|
from infer_linter import main as lint_main
|
|
73
|
-
sys.argv =
|
|
102
|
+
sys.argv = _forward_subcommand_args(args)
|
|
74
103
|
sys.exit(lint_main())
|
|
75
104
|
|
|
76
105
|
|
|
77
106
|
def cmd_heal(args):
|
|
107
|
+
"""Interacts with the central episodic self-healing solution memory cache."""
|
|
78
108
|
from cache_resolver import main as heal_main
|
|
79
|
-
sys.argv =
|
|
109
|
+
sys.argv = _forward_subcommand_args(args)
|
|
80
110
|
sys.exit(heal_main())
|
|
81
111
|
|
|
82
112
|
|
|
83
113
|
def cmd_distill(args):
|
|
114
|
+
"""Distills and filters high-volume CI/CD test execution logs by ~95%."""
|
|
84
115
|
from distill_log import main as distill_main
|
|
85
|
-
sys.argv =
|
|
116
|
+
sys.argv = _forward_subcommand_args(args)
|
|
86
117
|
sys.exit(distill_main())
|
|
87
118
|
|
|
88
119
|
|
|
89
120
|
def cmd_impact(args):
|
|
121
|
+
"""Analyzes code change impact and scopes affected tests using AST graph mapping."""
|
|
90
122
|
from test_impact import main as impact_main
|
|
91
|
-
sys.argv =
|
|
123
|
+
sys.argv = _forward_subcommand_args(args)
|
|
92
124
|
sys.exit(impact_main())
|
|
93
125
|
|
|
94
126
|
|
|
@@ -112,73 +144,99 @@ def cmd_clean(args):
|
|
|
112
144
|
try:
|
|
113
145
|
os.remove(os.path.join(root, f))
|
|
114
146
|
removed_count += 1
|
|
115
|
-
except
|
|
147
|
+
except OSError:
|
|
116
148
|
pass
|
|
117
149
|
print(f"✅ Cleanup finished: {removed_count} build artifacts and caches removed.")
|
|
118
150
|
|
|
119
151
|
|
|
120
152
|
def cmd_flaky(args):
|
|
153
|
+
"""Detects non-deterministic flaky tests and manages quarantine governance."""
|
|
121
154
|
from flaky_detector import main as flaky_main
|
|
122
|
-
sys.argv =
|
|
155
|
+
sys.argv = _forward_subcommand_args(args)
|
|
123
156
|
sys.exit(flaky_main())
|
|
124
157
|
|
|
125
158
|
|
|
126
159
|
def cmd_canary(args):
|
|
160
|
+
"""Executes the autonomous canary self-healing benchmark across 8 failure vectors."""
|
|
127
161
|
from agent_canary import main as canary_main
|
|
128
|
-
sys.argv =
|
|
162
|
+
sys.argv = _forward_subcommand_args(args)
|
|
129
163
|
sys.exit(canary_main())
|
|
130
164
|
|
|
131
165
|
|
|
132
166
|
def cmd_analyze(args):
|
|
167
|
+
"""Runs comprehensive 5-in-1 project health and AST architecture analysis."""
|
|
133
168
|
from analyze_project import main as analyze_main
|
|
134
|
-
sys.argv =
|
|
169
|
+
sys.argv = _forward_subcommand_args(args)
|
|
135
170
|
sys.exit(analyze_main())
|
|
136
171
|
|
|
137
172
|
|
|
138
173
|
def cmd_setup(args):
|
|
174
|
+
"""Bootstraps a target test repository with AI guide, Git hook, and AST map."""
|
|
139
175
|
from setup_project import main as setup_main
|
|
140
|
-
sys.argv =
|
|
176
|
+
sys.argv = _forward_subcommand_args(args)
|
|
141
177
|
sys.exit(setup_main())
|
|
142
178
|
|
|
143
179
|
|
|
180
|
+
def cmd_doctor(args):
|
|
181
|
+
"""Runs a 1-click diagnostic check of system environment, tools, and dependencies."""
|
|
182
|
+
from check_env import main as check_env_main
|
|
183
|
+
sys.argv = _forward_subcommand_args(args)
|
|
184
|
+
sys.exit(check_env_main())
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
def cmd_uninstall(args):
|
|
188
|
+
"""Reverts and cleans configuration files and Git hooks installed by setup in target project."""
|
|
189
|
+
from setup_project import uninstall_setup, resolve_target_repo
|
|
190
|
+
target = getattr(args, "target", None)
|
|
191
|
+
target_repo = resolve_target_repo(cli_target=target)
|
|
192
|
+
sys.exit(uninstall_setup(target_repo))
|
|
193
|
+
|
|
194
|
+
|
|
144
195
|
def cmd_auto_heal(args):
|
|
196
|
+
"""Executes closed-loop test failure diagnosis and creates a locator healing plan."""
|
|
145
197
|
from auto_heal import main as auto_heal_main
|
|
146
|
-
sys.argv =
|
|
198
|
+
sys.argv = _forward_subcommand_args(args)
|
|
147
199
|
sys.exit(auto_heal_main())
|
|
148
200
|
|
|
149
201
|
|
|
150
202
|
def cmd_safety_check(args):
|
|
203
|
+
"""Validates actions against the Action Safety Firewall to prevent destructive operations."""
|
|
151
204
|
from safety_firewall import main as safety_main
|
|
152
|
-
sys.argv =
|
|
205
|
+
sys.argv = _forward_subcommand_args(args)
|
|
153
206
|
sys.exit(safety_main())
|
|
154
207
|
|
|
155
208
|
|
|
156
209
|
def cmd_contract_drift(args):
|
|
210
|
+
"""Detects breaking API changes across OpenAPI / Swagger contract specifications."""
|
|
157
211
|
from api_drift_sentinel import main as drift_main
|
|
158
|
-
sys.argv =
|
|
212
|
+
sys.argv = _forward_subcommand_args(args)
|
|
159
213
|
sys.exit(drift_main())
|
|
160
214
|
|
|
161
215
|
|
|
162
216
|
def cmd_mcp_serve(args):
|
|
217
|
+
"""Starts the JSON-RPC 2.0 stdio Model Context Protocol (MCP) server."""
|
|
163
218
|
from mcp_server import run_stdio_server
|
|
164
219
|
run_stdio_server()
|
|
165
220
|
|
|
166
221
|
|
|
167
222
|
def cmd_mutate(args):
|
|
223
|
+
"""Injects syntactic micro-mutations to measure test assertion sensitivity."""
|
|
168
224
|
from micro_mutator import main as mut_main
|
|
169
|
-
sys.argv =
|
|
225
|
+
sys.argv = _forward_subcommand_args(args)
|
|
170
226
|
sys.exit(mut_main())
|
|
171
227
|
|
|
172
228
|
|
|
173
229
|
def cmd_heal_pr(args):
|
|
230
|
+
"""Calculates self-healing confidence and generates an automated Git pull request draft."""
|
|
174
231
|
from heal_pr_automator import main as pr_main
|
|
175
|
-
sys.argv =
|
|
232
|
+
sys.argv = _forward_subcommand_args(args)
|
|
176
233
|
sys.exit(pr_main())
|
|
177
234
|
|
|
178
235
|
|
|
179
236
|
def cmd_shard(args):
|
|
237
|
+
"""Balances parallel CI/CD test execution using duration-balanced bin-packing."""
|
|
180
238
|
from matrix_sharder import main as shard_main
|
|
181
|
-
sys.argv =
|
|
239
|
+
sys.argv = _forward_subcommand_args(args)
|
|
182
240
|
sys.exit(shard_main())
|
|
183
241
|
|
|
184
242
|
|
|
@@ -217,25 +275,37 @@ def cmd_omni_scan(args):
|
|
|
217
275
|
|
|
218
276
|
def cmd_report_bug(args):
|
|
219
277
|
from bug_reporter import main as bug_main
|
|
220
|
-
sys.argv =
|
|
278
|
+
sys.argv = _forward_subcommand_args(args)
|
|
221
279
|
sys.exit(bug_main())
|
|
222
280
|
|
|
223
281
|
|
|
224
282
|
def cmd_mock_shield(args):
|
|
225
283
|
from network_mock_shield import main as mock_main
|
|
226
|
-
sys.argv =
|
|
284
|
+
sys.argv = _forward_subcommand_args(args)
|
|
227
285
|
sys.exit(mock_main())
|
|
228
286
|
|
|
229
287
|
|
|
230
288
|
def cmd_visual_mask(args):
|
|
231
289
|
from smart_visual_masker import main as mask_main
|
|
232
|
-
sys.argv =
|
|
290
|
+
sys.argv = _forward_subcommand_args(args)
|
|
233
291
|
sys.exit(mask_main())
|
|
234
292
|
|
|
235
293
|
|
|
294
|
+
def cmd_review_spec(args):
|
|
295
|
+
from goldfish_review import main as review_main
|
|
296
|
+
sys.argv = _forward_subcommand_args(args)
|
|
297
|
+
sys.exit(review_main())
|
|
298
|
+
|
|
299
|
+
|
|
300
|
+
def cmd_drift_check(args):
|
|
301
|
+
from spec_drift_sentinel import main as drift_main
|
|
302
|
+
sys.argv = _forward_subcommand_args(args)
|
|
303
|
+
sys.exit(drift_main())
|
|
304
|
+
|
|
305
|
+
|
|
236
306
|
def cmd_ci_hook(args):
|
|
237
307
|
from ci_healing_hook import main as hook_main
|
|
238
|
-
sys.argv =
|
|
308
|
+
sys.argv = _forward_subcommand_args(args)
|
|
239
309
|
sys.exit(hook_main())
|
|
240
310
|
|
|
241
311
|
|
|
@@ -259,8 +329,8 @@ def cmd_migrate(args):
|
|
|
259
329
|
try:
|
|
260
330
|
transpile_file(file_path, target, output_dir=dest, hermetic=True)
|
|
261
331
|
migrated_count += 1
|
|
262
|
-
except
|
|
263
|
-
|
|
332
|
+
except (OSError, ValueError, SyntaxError) as e:
|
|
333
|
+
print(f" ⚠️ Skipping {f}: {e}")
|
|
264
334
|
print(f"✅ [MIGRATION COMPLETE] {migrated_count} test files converted to {target} in '{dest}'.")
|
|
265
335
|
else:
|
|
266
336
|
transpile_file(src, target, output_dir=dest, hermetic=True)
|
|
@@ -269,55 +339,67 @@ def cmd_migrate(args):
|
|
|
269
339
|
|
|
270
340
|
def cmd_decouple_config(args):
|
|
271
341
|
from config_decoupler import main as decouple_main
|
|
272
|
-
sys.argv =
|
|
342
|
+
sys.argv = _forward_subcommand_args(args)
|
|
273
343
|
sys.exit(decouple_main())
|
|
274
344
|
|
|
275
345
|
|
|
276
346
|
def cmd_fuzz_api(args):
|
|
277
347
|
from api_fuzzer import main as fuzz_main
|
|
278
|
-
sys.argv =
|
|
348
|
+
sys.argv = _forward_subcommand_args(args)
|
|
279
349
|
sys.exit(fuzz_main())
|
|
280
350
|
|
|
281
351
|
|
|
282
352
|
def cmd_som(args):
|
|
283
353
|
from visual_som_helper import main as som_main
|
|
284
|
-
sys.argv =
|
|
354
|
+
sys.argv = _forward_subcommand_args(args)
|
|
285
355
|
sys.exit(som_main())
|
|
286
356
|
|
|
287
357
|
|
|
358
|
+
def cmd_gherkin(args):
|
|
359
|
+
from gherkin_suite import main as gherkin_main
|
|
360
|
+
sys.argv = _forward_subcommand_args(args)
|
|
361
|
+
sys.exit(gherkin_main())
|
|
362
|
+
|
|
363
|
+
|
|
288
364
|
def cmd_export_postman(args):
|
|
289
365
|
from export_postman_collection import main as postman_main
|
|
290
|
-
sys.argv =
|
|
366
|
+
sys.argv = _forward_subcommand_args(args)
|
|
291
367
|
sys.exit(postman_main())
|
|
292
368
|
|
|
293
369
|
|
|
294
370
|
def cmd_generate_jmx(args):
|
|
295
371
|
from generate_jmx_plan import main as jmx_main
|
|
296
|
-
sys.argv =
|
|
372
|
+
sys.argv = _forward_subcommand_args(args)
|
|
297
373
|
sys.exit(jmx_main())
|
|
298
374
|
|
|
299
375
|
|
|
300
376
|
def cmd_skillspector(args):
|
|
301
377
|
from skillspector import main as skillspector_main
|
|
302
|
-
sys.argv =
|
|
378
|
+
sys.argv = _forward_subcommand_args(args)
|
|
303
379
|
sys.exit(skillspector_main())
|
|
304
380
|
|
|
305
381
|
|
|
306
382
|
def cmd_analyze_jtl(args):
|
|
307
383
|
from jtl_analyzer import main as jtl_main
|
|
308
|
-
sys.argv =
|
|
384
|
+
sys.argv = _forward_subcommand_args(args)
|
|
309
385
|
sys.exit(jtl_main())
|
|
310
386
|
|
|
311
387
|
|
|
388
|
+
def cmd_export_excel(args):
|
|
389
|
+
from md_to_xlsx import main as excel_main
|
|
390
|
+
sys.argv = _forward_subcommand_args(args)
|
|
391
|
+
sys.exit(excel_main())
|
|
392
|
+
|
|
393
|
+
|
|
312
394
|
def cmd_correlate_telemetry(args):
|
|
313
395
|
from telemetry_correlator import main as telem_main
|
|
314
|
-
sys.argv =
|
|
396
|
+
sys.argv = _forward_subcommand_args(args)
|
|
315
397
|
sys.exit(telem_main())
|
|
316
398
|
|
|
317
399
|
|
|
318
400
|
def cmd_analyze_newman(args):
|
|
319
401
|
from newman_analyzer import main as newman_main
|
|
320
|
-
sys.argv =
|
|
402
|
+
sys.argv = _forward_subcommand_args(args)
|
|
321
403
|
sys.exit(newman_main())
|
|
322
404
|
|
|
323
405
|
|
|
@@ -336,17 +418,161 @@ def cmd_update(args):
|
|
|
336
418
|
update_sentinel.perform_update()
|
|
337
419
|
|
|
338
420
|
|
|
421
|
+
def cmd_tokens(args):
|
|
422
|
+
import count_tokens
|
|
423
|
+
sys.argv = _forward_subcommand_args(args)
|
|
424
|
+
count_tokens.main()
|
|
425
|
+
|
|
426
|
+
|
|
427
|
+
def cmd_dashboard(args):
|
|
428
|
+
import dashboard_generator
|
|
429
|
+
sys.argv = _forward_subcommand_args(args)
|
|
430
|
+
dashboard_generator.main()
|
|
431
|
+
|
|
432
|
+
|
|
433
|
+
def cmd_watch(args):
|
|
434
|
+
import watch_mode
|
|
435
|
+
sys.argv = _forward_subcommand_args(args)
|
|
436
|
+
watch_mode.main()
|
|
437
|
+
|
|
438
|
+
|
|
439
|
+
def cmd_welcome(args):
|
|
440
|
+
import welcome_page
|
|
441
|
+
sys.argv = _forward_subcommand_args(args)
|
|
442
|
+
welcome_page.main()
|
|
443
|
+
|
|
444
|
+
|
|
445
|
+
def cmd_wcag_audit(args):
|
|
446
|
+
from wcag_audit import main as wcag_main
|
|
447
|
+
sys.argv = _forward_subcommand_args(args)
|
|
448
|
+
sys.exit(wcag_main())
|
|
449
|
+
|
|
450
|
+
|
|
451
|
+
def cmd_lookup_tc(args):
|
|
452
|
+
from lookup_tc import main as tc_main
|
|
453
|
+
sys.argv = _forward_subcommand_args(args)
|
|
454
|
+
sys.exit(tc_main())
|
|
455
|
+
|
|
456
|
+
|
|
457
|
+
def cmd_lookup_xpath(args):
|
|
458
|
+
from lookup_xpath import main as xpath_main
|
|
459
|
+
sys.argv = _forward_subcommand_args(args)
|
|
460
|
+
sys.exit(xpath_main())
|
|
461
|
+
|
|
462
|
+
|
|
463
|
+
def cmd_trace_data_flow(args):
|
|
464
|
+
from trace_data_flow import main as tdf_main
|
|
465
|
+
sys.argv = _forward_subcommand_args(args)
|
|
466
|
+
sys.exit(tdf_main())
|
|
467
|
+
|
|
468
|
+
|
|
469
|
+
def cmd_generate_tc(args):
|
|
470
|
+
from generate_tc_from_story import main as gen_tc_main
|
|
471
|
+
sys.argv = _forward_subcommand_args(args)
|
|
472
|
+
sys.exit(gen_tc_main())
|
|
473
|
+
|
|
474
|
+
|
|
475
|
+
def cmd_pinpoint_failure(args):
|
|
476
|
+
from pinpoint_failure import main as pp_main
|
|
477
|
+
sys.argv = _forward_subcommand_args(args)
|
|
478
|
+
sys.exit(pp_main())
|
|
479
|
+
|
|
480
|
+
|
|
481
|
+
def cmd_sync_rules(args):
|
|
482
|
+
from sync_agent_rules import main as sync_rules_main
|
|
483
|
+
sys.argv = _forward_subcommand_args(args)
|
|
484
|
+
sys.exit(sync_rules_main())
|
|
485
|
+
|
|
486
|
+
|
|
487
|
+
def cmd_api_matrix(args):
|
|
488
|
+
from generate_api_matrix import main as api_matrix_main
|
|
489
|
+
sys.argv = _forward_subcommand_args(args)
|
|
490
|
+
sys.exit(api_matrix_main())
|
|
491
|
+
|
|
492
|
+
|
|
493
|
+
def cmd_canvas_diff(args):
|
|
494
|
+
from visual_diff_canvas import main as canvas_diff_main
|
|
495
|
+
sys.argv = _forward_subcommand_args(args)
|
|
496
|
+
sys.exit(canvas_diff_main())
|
|
497
|
+
|
|
498
|
+
|
|
499
|
+
def cmd_validate_groovy(args):
|
|
500
|
+
from validate_groovy_scripts import main as groovy_main
|
|
501
|
+
sys.argv = _forward_subcommand_args(args)
|
|
502
|
+
sys.exit(groovy_main())
|
|
503
|
+
|
|
504
|
+
|
|
505
|
+
def cmd_check_version(args):
|
|
506
|
+
from check_version_sync import main as ver_sync_main
|
|
507
|
+
sys.argv = _forward_subcommand_args(args)
|
|
508
|
+
sys.exit(ver_sync_main())
|
|
509
|
+
|
|
510
|
+
|
|
511
|
+
def cmd_mcp_excel(args):
|
|
512
|
+
from mcp_excel_server import main as mcp_excel_main
|
|
513
|
+
sys.argv = _forward_subcommand_args(args)
|
|
514
|
+
sys.exit(mcp_excel_main())
|
|
515
|
+
|
|
516
|
+
|
|
517
|
+
def _hub_version():
|
|
518
|
+
manifest_path = os.path.join(REPO_ROOT, "skills_manifest.json")
|
|
519
|
+
version = "2.4.1"
|
|
520
|
+
if os.path.exists(manifest_path):
|
|
521
|
+
try:
|
|
522
|
+
import json
|
|
523
|
+
with open(manifest_path, "r", encoding="utf-8") as f:
|
|
524
|
+
version = json.load(f).get("version", version)
|
|
525
|
+
except (OSError, json.JSONDecodeError):
|
|
526
|
+
pass
|
|
527
|
+
return version
|
|
528
|
+
|
|
529
|
+
|
|
530
|
+
class SynapseArgumentParser(argparse.ArgumentParser):
|
|
531
|
+
"""Enhanced ArgumentParser providing fuzzy Did-You-Mean suggestions on command typos."""
|
|
532
|
+
def error(self, message):
|
|
533
|
+
import difflib
|
|
534
|
+
m = re.search(r"invalid choice: '([^']+)'", message)
|
|
535
|
+
if m:
|
|
536
|
+
bad_choice = m.group(1)
|
|
537
|
+
choices = []
|
|
538
|
+
for action in self._actions:
|
|
539
|
+
if isinstance(action, argparse._SubParsersAction):
|
|
540
|
+
choices = list(action.choices.keys())
|
|
541
|
+
break
|
|
542
|
+
matches = difflib.get_close_matches(bad_choice, choices, n=3, cutoff=0.4)
|
|
543
|
+
sys.stderr.write(f"\n{BOLD}{RED}❌ Error: Lệnh '{bad_choice}' không tồn tại trong Synapse-Hub.{RESET}\n")
|
|
544
|
+
if matches:
|
|
545
|
+
suggestions = ", ".join(f"{BOLD}{GREEN}{c}{RESET}" for c in matches)
|
|
546
|
+
sys.stderr.write(f"💡 Có phải ý bạn là: {suggestions} ?\n\n")
|
|
547
|
+
sys.stderr.write(f"👉 Thử chạy: {BOLD}agent-qa {matches[0]} --help{RESET}\n\n")
|
|
548
|
+
else:
|
|
549
|
+
sys.stderr.write(f"👉 Gõ {BOLD}agent-qa --help{RESET} để xem danh sách tất cả các lệnh khả dụng.\n\n")
|
|
550
|
+
sys.exit(2)
|
|
551
|
+
super().error(message)
|
|
552
|
+
|
|
553
|
+
|
|
339
554
|
def main():
|
|
340
|
-
parser =
|
|
555
|
+
parser = SynapseArgumentParser(
|
|
341
556
|
prog="agent-qa",
|
|
342
557
|
description="Enterprise AI Agent Quality Engineering & Test Automation Hub CLI"
|
|
343
558
|
)
|
|
559
|
+
parser.add_argument(
|
|
560
|
+
"--version",
|
|
561
|
+
action="version",
|
|
562
|
+
version=f"Agent-QA Hub CLI v{_hub_version()}"
|
|
563
|
+
)
|
|
344
564
|
parser.add_argument(
|
|
345
565
|
"--offline", "--offline-deterministic",
|
|
346
566
|
action="store_true",
|
|
347
567
|
dest="offline",
|
|
348
568
|
help="Force 100%% offline air-gapped deterministic mode (zero external network / LLM API calls)"
|
|
349
569
|
)
|
|
570
|
+
parser.add_argument(
|
|
571
|
+
"-q", "--quiet",
|
|
572
|
+
action="store_true",
|
|
573
|
+
dest="quiet",
|
|
574
|
+
help="Suppress informational banners and output only critical verdicts"
|
|
575
|
+
)
|
|
350
576
|
subparsers = parser.add_subparsers(dest="subcommand", help="Available subcommands")
|
|
351
577
|
|
|
352
578
|
# version
|
|
@@ -357,6 +583,18 @@ def main():
|
|
|
357
583
|
p_setup = subparsers.add_parser("setup", help="Autonomous 1-click bootstrap of target project (AI guide, Git hook, AST map)")
|
|
358
584
|
p_setup.set_defaults(func=cmd_setup)
|
|
359
585
|
|
|
586
|
+
# doctor
|
|
587
|
+
p_doctor = subparsers.add_parser("doctor", description="Enterprise Environment Diagnostic Tool", help="Run 1-click diagnostic check of system environment, tools, and dependencies")
|
|
588
|
+
p_doctor.add_argument("target", nargs="?", default=None, help="Target repository path to diagnose")
|
|
589
|
+
p_doctor.add_argument("--repo", "--path", dest="repo_path", default=None, help="Target repository path")
|
|
590
|
+
p_doctor.add_argument("--insecure", action="store_true", help="Allow unverified SSL certificates during connectivity checks")
|
|
591
|
+
p_doctor.set_defaults(func=cmd_doctor)
|
|
592
|
+
|
|
593
|
+
# uninstall
|
|
594
|
+
p_uninstall = subparsers.add_parser("uninstall", help="Revert and remove files installed by setup in target project")
|
|
595
|
+
p_uninstall.add_argument("target", nargs="?", default=None, help="Target repository path to revert")
|
|
596
|
+
p_uninstall.set_defaults(func=cmd_uninstall)
|
|
597
|
+
|
|
360
598
|
# auto-heal
|
|
361
599
|
p_auto_heal = subparsers.add_parser("auto-heal", help="Autonomous closed-loop test failure diagnosis and healing plan")
|
|
362
600
|
p_auto_heal.set_defaults(func=cmd_auto_heal)
|
|
@@ -366,7 +604,7 @@ def main():
|
|
|
366
604
|
p_heal_pr.set_defaults(func=cmd_heal_pr)
|
|
367
605
|
|
|
368
606
|
# mutate
|
|
369
|
-
p_mut = subparsers.add_parser("mutate", help="Inject
|
|
607
|
+
p_mut = subparsers.add_parser("mutate", help="Inject syntactic micro-mutants to verify test assertion strength")
|
|
370
608
|
p_mut.set_defaults(func=cmd_mutate)
|
|
371
609
|
|
|
372
610
|
# shard
|
|
@@ -390,7 +628,7 @@ def main():
|
|
|
390
628
|
p_analyze.set_defaults(func=cmd_analyze)
|
|
391
629
|
|
|
392
630
|
# verify
|
|
393
|
-
p_verify = subparsers.add_parser("verify", help="Execute
|
|
631
|
+
p_verify = subparsers.add_parser("verify", help="Execute 9 Quality Gates DoD Verification")
|
|
394
632
|
p_verify.set_defaults(func=cmd_verify)
|
|
395
633
|
|
|
396
634
|
# lint
|
|
@@ -409,6 +647,10 @@ def main():
|
|
|
409
647
|
p_impact = subparsers.add_parser("impact", help="Analyze code change impact using AST Knowledge Graph")
|
|
410
648
|
p_impact.set_defaults(func=cmd_impact)
|
|
411
649
|
|
|
650
|
+
# gherkin
|
|
651
|
+
p_gherkin = subparsers.add_parser("gherkin", help="Compile Gherkin .feature files into test matrix, Universal IR and coverage-gap report (0-token)")
|
|
652
|
+
p_gherkin.set_defaults(func=cmd_gherkin)
|
|
653
|
+
|
|
412
654
|
# canary
|
|
413
655
|
p_canary = subparsers.add_parser("canary", help="Run autonomous canary resilience benchmark")
|
|
414
656
|
p_canary.set_defaults(func=cmd_canary)
|
|
@@ -484,6 +726,13 @@ def main():
|
|
|
484
726
|
p_jtl = subparsers.add_parser("analyze-jtl", help="Analyze JMeter .jtl results, evaluate P90/P95/P99 SLA, and enforce CI/CD Quality Gate")
|
|
485
727
|
p_jtl.set_defaults(func=cmd_analyze_jtl)
|
|
486
728
|
|
|
729
|
+
# export-excel
|
|
730
|
+
p_excel = subparsers.add_parser("export-excel", help="Convert Markdown Test Cases into Styled Enterprise Excel (.xlsx)")
|
|
731
|
+
p_excel.add_argument("input", nargs="?", help="Path to input Markdown file (.md)")
|
|
732
|
+
p_excel.add_argument("-o", "--output", help="Path to output Excel file (.xlsx)")
|
|
733
|
+
p_excel.add_argument("--sheet-name", default="Test Cases", help="Worksheet title (default: Test Cases)")
|
|
734
|
+
p_excel.set_defaults(func=cmd_export_excel)
|
|
735
|
+
|
|
487
736
|
# correlate-telemetry
|
|
488
737
|
p_telemetry = subparsers.add_parser("correlate-telemetry", help="Correlate Client-Side JMeter latency with Server-Side APM CPU/RAM/DB telemetry")
|
|
489
738
|
p_telemetry.set_defaults(func=cmd_correlate_telemetry)
|
|
@@ -509,25 +758,188 @@ def main():
|
|
|
509
758
|
p_author = subparsers.add_parser("verify-author", help="Verify author attribution, provenance, and anti-tamper integrity")
|
|
510
759
|
p_author.set_defaults(func=cmd_verify_author)
|
|
511
760
|
|
|
761
|
+
# tokens (Cross-Platform Token & Cost Auditor)
|
|
762
|
+
p_tokens = subparsers.add_parser("tokens", help="Audit token usage and estimated API cost across Antigravity, Cursor, and Claude Code")
|
|
763
|
+
p_tokens.add_argument("--platform", "-p", choices=["auto", "antigravity", "cursor", "claude", "all"], default="auto", help="AI platform to audit (default: auto)")
|
|
764
|
+
p_tokens.add_argument("--session", type=str, help="Specific session ID or index to audit")
|
|
765
|
+
p_tokens.add_argument("--current", action="store_true", help="Audit current active conversation")
|
|
766
|
+
p_tokens.add_argument("--last", action="store_true", help="Audit previous completed session (default)")
|
|
767
|
+
p_tokens.add_argument("--last-task", action="store_true", help="Audit specifically the last turn of target session")
|
|
768
|
+
p_tokens.add_argument("--turns", action="store_true", help="Show full turn-by-turn breakdown table")
|
|
769
|
+
p_tokens.add_argument("--rolling", "--budget", action="store_true", dest="rolling", help="Show 5-hour and 7-day rolling window quota & remaining tokens")
|
|
770
|
+
p_tokens.add_argument("--savings", action="store_true", help="Show Hub vs. Non-Hub token and cost savings comparison")
|
|
771
|
+
p_tokens.add_argument("--header", action="store_true", help="Print Pre-Flight confirmation block lines")
|
|
772
|
+
p_tokens.add_argument("--list", action="store_true", help="List recent conversations")
|
|
773
|
+
p_tokens.add_argument("--pricing", choices=["gemini-flash", "gemini-pro", "claude-sonnet", "claude-opus", "gpt-4o", "gpt-4o-mini"], default=None, help="Model pricing basis (default: auto-detected)")
|
|
774
|
+
p_tokens.add_argument("--json", action="store_true", help="Output machine-readable JSON format")
|
|
775
|
+
p_tokens.add_argument("--file", type=str, help="Direct path to a transcript.jsonl file")
|
|
776
|
+
p_tokens.set_defaults(func=cmd_tokens)
|
|
777
|
+
|
|
778
|
+
# dashboard (Standalone One-Page HTML Executive Dashboard)
|
|
779
|
+
p_dashboard = subparsers.add_parser("dashboard", help="Generate standalone one-page executive HTML dashboard (zero CDN deps)")
|
|
780
|
+
p_dashboard.add_argument("target", nargs="?", default=None, help="Target repository directory (default: current or Hub)")
|
|
781
|
+
p_dashboard.add_argument("--output", "-o", help="Output HTML file path (default: <target>/reports/PROJECT_DASHBOARD.html)")
|
|
782
|
+
p_dashboard.add_argument("--open", action="store_true", help="Automatically open generated dashboard in default browser")
|
|
783
|
+
p_dashboard.add_argument("--json", action="store_true", help="Print summary JSON to stdout")
|
|
784
|
+
p_dashboard.add_argument("--lang", choices=["vi", "en"], default="vi", help="Default display language (vi: Tiếng Việt, en: English, default: vi)")
|
|
785
|
+
p_dashboard.set_defaults(func=cmd_dashboard)
|
|
786
|
+
|
|
787
|
+
# watch (Real-Time Incremental Watch Mode Sentinel)
|
|
788
|
+
p_watch = subparsers.add_parser("watch", help="Real-Time incremental watch mode & test engineering HUD (< 100ms feedback)")
|
|
789
|
+
p_watch.add_argument("target", nargs="?", default=".", help="Directory to monitor (default: current directory)")
|
|
790
|
+
p_watch.add_argument("--debounce", type=float, default=0.8, help="Debounce interval in seconds (default: 0.8)")
|
|
791
|
+
p_watch.add_argument("--inactivity-timeout", type=float, default=0.0, help="Inactivity timeout in seconds to trigger stuck warning (default: 0 = disabled)")
|
|
792
|
+
p_watch.add_argument("--once", action="store_true", help="Run incremental scan once on all files and exit")
|
|
793
|
+
p_watch.set_defaults(func=cmd_watch)
|
|
794
|
+
|
|
795
|
+
# welcome (Interactive Visual Landing Page)
|
|
796
|
+
p_welcome = subparsers.add_parser("welcome", description="Interactive Visual Landing Page", help="Launch interactive visual landing page introducing Synapse Hub")
|
|
797
|
+
p_welcome.add_argument("target", nargs="?", default=None, help="Target repository directory (default: current directory)")
|
|
798
|
+
p_welcome.add_argument("--output", "-o", default=None, help="Output HTML file path (default: reports/WELCOME.html)")
|
|
799
|
+
p_welcome.add_argument("--lang", choices=["vi", "en"], default="vi", help="Default initial language (default: vi = Vietnamese)")
|
|
800
|
+
p_welcome.add_argument("--no-browser", action="store_true", help="Do not open the browser after generating the page")
|
|
801
|
+
p_welcome.add_argument("--open", action="store_true", help="Explicitly open the browser")
|
|
802
|
+
p_welcome.add_argument("--first-run", action="store_true", help="Only open if running for the first time (e.g. npm install or first pull)")
|
|
803
|
+
p_welcome.set_defaults(func=cmd_welcome)
|
|
804
|
+
|
|
805
|
+
# wcag-audit (WCAG 2.2 Accessibility Sentinel)
|
|
806
|
+
p_wcag = subparsers.add_parser("wcag-audit", help="Audit WCAG 2.2 accessibility conformance and contrast ratios")
|
|
807
|
+
p_wcag.add_argument("target", nargs="?", default=".", help="Target HTML file or directory to audit")
|
|
808
|
+
p_wcag.set_defaults(func=cmd_wcag_audit)
|
|
809
|
+
|
|
810
|
+
# lookup-tc (Deterministic Test Case Identifier Index)
|
|
811
|
+
p_lookup_tc = subparsers.add_parser("lookup-tc", help="Search test cases by ID, tag, priority, or flow")
|
|
812
|
+
p_lookup_tc.add_argument("query", nargs="?", default="", help="Query keyword or TC ID")
|
|
813
|
+
p_lookup_tc.set_defaults(func=cmd_lookup_tc)
|
|
814
|
+
|
|
815
|
+
# lookup-xpath (AOM & DOM Selector Lookup Cache)
|
|
816
|
+
p_lookup_xpath = subparsers.add_parser("lookup-xpath", help="Query cached resilient XPath & AOM locators")
|
|
817
|
+
p_lookup_xpath.add_argument("query", nargs="?", default="", help="Element text, test-id, or locator label")
|
|
818
|
+
p_lookup_xpath.set_defaults(func=cmd_lookup_xpath)
|
|
819
|
+
|
|
820
|
+
# trace-data-flow (Idempotent Data Flow & Taint Analysis)
|
|
821
|
+
p_trace = subparsers.add_parser("trace-data-flow", help="Trace test data lifecycles to detect DB leaks and missing teardowns")
|
|
822
|
+
p_trace.add_argument("target", nargs="?", default=".", help="Target test directory to inspect")
|
|
823
|
+
p_trace.set_defaults(func=cmd_trace_data_flow)
|
|
824
|
+
|
|
825
|
+
# generate-tc (User Story & Acceptance Criteria Compiler)
|
|
826
|
+
p_gen_tc = subparsers.add_parser("generate-tc", help="Compile natural language user stories into Clean POM test cases")
|
|
827
|
+
p_gen_tc.add_argument("story_file", nargs="?", default="", help="Path to markdown/text user story specification")
|
|
828
|
+
p_gen_tc.set_defaults(func=cmd_generate_tc)
|
|
829
|
+
|
|
830
|
+
# pinpoint-failure (Instant JUnit XML Root Cause Autopsy)
|
|
831
|
+
p_pinpoint = subparsers.add_parser("pinpoint-failure", help="Parse JUnit XML and locate exact failing line in 0.1s")
|
|
832
|
+
p_pinpoint.add_argument("report_file", nargs="?", default="", help="Path to JUnit XML test report")
|
|
833
|
+
p_pinpoint.set_defaults(func=cmd_pinpoint_failure)
|
|
834
|
+
|
|
835
|
+
# sync-rules (Single-Source Agent Rules Synchronizer)
|
|
836
|
+
p_sync_rules = subparsers.add_parser("sync-rules", help="Synchronize AGENTS.md single source of truth across all AI IDE bridges")
|
|
837
|
+
p_sync_rules.add_argument("--check", action="store_true", help="Verify all AI bridges are in sync without writing")
|
|
838
|
+
p_sync_rules.set_defaults(func=cmd_sync_rules)
|
|
839
|
+
|
|
840
|
+
# review-spec (Zero-Context Test Spec Auditor - Elephant-Goldfish Model)
|
|
841
|
+
p_review = subparsers.add_parser("review-spec", help="Zero-context stress-test for specifications and user stories (Elephant-Goldfish Model)")
|
|
842
|
+
p_review.add_argument("spec_file", nargs="?", default="", help="Path to specification file (Markdown or Gherkin .feature, use '-' for stdin)")
|
|
843
|
+
p_review.add_argument("--stdin", action="store_true", help="Read specification from standard input (stdin)")
|
|
844
|
+
p_review.add_argument("--json", action="store_true", help="Output machine-readable JSON format")
|
|
845
|
+
p_review.add_argument("--min-score", type=int, default=80, help="Minimum readiness score threshold (default: 80)")
|
|
846
|
+
p_review.set_defaults(func=cmd_review_spec)
|
|
847
|
+
|
|
848
|
+
# drift-check (Spec-to-Code Drift Sentinel)
|
|
849
|
+
p_drift = subparsers.add_parser("drift-check", help="Spec-to-Code Drift Sentinel checking Deficit & Scope Drift")
|
|
850
|
+
p_drift.add_argument("--spec", required=True, help="Path to specification file (Markdown or Gherkin .feature)")
|
|
851
|
+
p_drift.add_argument("--code", required=True, help="Path to test script or directory of test scripts")
|
|
852
|
+
p_drift.add_argument("--markdown", "-m", help="Path to export Markdown drift report (e.g. SPEC_DRIFT_REPORT.md)")
|
|
853
|
+
p_drift.add_argument("--json", action="store_true", help="Output machine-readable JSON format")
|
|
854
|
+
p_drift.set_defaults(func=cmd_drift_check)
|
|
855
|
+
|
|
856
|
+
# api-matrix
|
|
857
|
+
p_api_mat = subparsers.add_parser("api-matrix", help="Generate Positive, Boundary, and Negative test matrix from OpenAPI/Swagger")
|
|
858
|
+
p_api_mat.add_argument("--spec", "-s", help="Path to OpenAPI / Swagger JSON/YAML file")
|
|
859
|
+
p_api_mat.add_argument("--format", "-f", choices=["markdown", "json"], default="markdown", help="Output format (markdown, json)")
|
|
860
|
+
p_api_mat.add_argument("--output", "-o", help="Output file path")
|
|
861
|
+
p_api_mat.add_argument("--sample", action="store_true", help="Generate a sample matrix using built-in demonstration schema")
|
|
862
|
+
p_api_mat.set_defaults(func=cmd_api_matrix)
|
|
863
|
+
|
|
864
|
+
# canvas-diff
|
|
865
|
+
p_canvas = subparsers.add_parser("canvas-diff", help="HTML5 Canvas visual regression diffing & blank check")
|
|
866
|
+
p_canvas.add_argument("canvas_args", nargs="*", help="Subcommand (compare/check-blank) and image paths")
|
|
867
|
+
p_canvas.set_defaults(func=cmd_canvas_diff)
|
|
868
|
+
|
|
869
|
+
# validate-groovy
|
|
870
|
+
p_groovy = subparsers.add_parser("validate-groovy", help="Pre-check Groovy scripts & keywords syntax balance")
|
|
871
|
+
p_groovy.add_argument("target", nargs="?", default=None, help="Target repository or file to validate")
|
|
872
|
+
p_groovy.add_argument("--dir", "-d", help="Explicit directory to scan")
|
|
873
|
+
p_groovy.set_defaults(func=cmd_validate_groovy)
|
|
874
|
+
|
|
875
|
+
# check-version
|
|
876
|
+
p_ver_sync = subparsers.add_parser("check-version", help="Verify universal version synchronization across all files")
|
|
877
|
+
p_ver_sync.add_argument("--expected-version", "-e", help="Expected version string (e.g. from git tag)", default=None)
|
|
878
|
+
p_ver_sync.set_defaults(func=cmd_check_version)
|
|
879
|
+
|
|
880
|
+
# mcp-excel
|
|
881
|
+
p_mcp_excel = subparsers.add_parser("mcp-excel", help="Start the JSON-RPC 2.0 stdio MCP Excel server")
|
|
882
|
+
p_mcp_excel.set_defaults(func=cmd_mcp_excel)
|
|
883
|
+
|
|
512
884
|
args, unknown = parser.parse_known_args()
|
|
513
885
|
if getattr(args, "offline", False):
|
|
514
886
|
os.environ["AGENT_QA_OFFLINE"] = "1"
|
|
515
887
|
print("🔒 [OFFLINE MODE] Air-Gapped Deterministic Mode Active. 100% Local AST & Heuristics (Zero External API calls).")
|
|
516
888
|
|
|
517
889
|
if not args.subcommand:
|
|
890
|
+
# If running in an interactive terminal, offer a friendly quick-start menu
|
|
891
|
+
is_interactive = hasattr(sys.stdin, "isatty") and sys.stdin.isatty() and not os.environ.get("CI") and not os.environ.get("SYNAPSE_NON_INTERACTIVE")
|
|
892
|
+
if is_interactive:
|
|
893
|
+
print(f"\n{BOLD}{CYAN}======================================================================{RESET}")
|
|
894
|
+
print(f"{BOLD}{CYAN} 🧠 SYNAPSE HUB — INTERACTIVE TERMINAL WIZARD {RESET}")
|
|
895
|
+
print(f"{BOLD}{CYAN}======================================================================{RESET}")
|
|
896
|
+
print("Chào bạn! Hãy chọn nhanh một tác vụ để bắt đầu (hoặc nhấn Enter để xem Trợ Giúp):")
|
|
897
|
+
print(f" {BOLD}1.{RESET} 🩺 {BOLD}Doctor{RESET} - Kiểm tra chẩn đoán môi trường (Node, Python, Chrome, Git)")
|
|
898
|
+
print(f" {BOLD}2.{RESET} 🚀 {BOLD}Setup{RESET} - Thiết lập bảo vệ 1-click cho dự án kiểm thử mục tiêu")
|
|
899
|
+
print(f" {BOLD}3.{RESET} 🔍 {BOLD}Lint{RESET} - Quét phát hiện test pass ảo, 0 assert, sleep cứng")
|
|
900
|
+
print(f" {BOLD}4.{RESET} 🛡️ {BOLD}Verify{RESET} - Chạy kiểm tra 9 Cổng Chất Lượng DoD")
|
|
901
|
+
print(f" {BOLD}5.{RESET} 🌐 {BOLD}Welcome{RESET} - Mở trang Landing Page trực quan")
|
|
902
|
+
print(f" {BOLD}6.{RESET} ❓ {BOLD}Help{RESET} - Xem danh sách đầy đủ tất cả các lệnh CLI")
|
|
903
|
+
print(f"{BOLD}{CYAN}======================================================================{RESET}")
|
|
904
|
+
try:
|
|
905
|
+
choice = input(f"Nhập lựa chọn {BOLD}[1-6]{RESET} (mặc định: 6): ").strip()
|
|
906
|
+
except (EOFError, KeyboardInterrupt):
|
|
907
|
+
print()
|
|
908
|
+
sys.exit(0)
|
|
909
|
+
|
|
910
|
+
if choice == "1":
|
|
911
|
+
args.subcommand = "doctor"
|
|
912
|
+
return cmd_doctor(args)
|
|
913
|
+
elif choice == "2":
|
|
914
|
+
args.subcommand = "setup"
|
|
915
|
+
return cmd_setup(args)
|
|
916
|
+
elif choice == "3":
|
|
917
|
+
args.subcommand = "lint"
|
|
918
|
+
return cmd_lint(args)
|
|
919
|
+
elif choice == "4":
|
|
920
|
+
args.subcommand = "verify"
|
|
921
|
+
return cmd_verify(args)
|
|
922
|
+
elif choice == "5":
|
|
923
|
+
args.subcommand = "welcome"
|
|
924
|
+
return cmd_welcome(args)
|
|
925
|
+
|
|
518
926
|
parser.print_help()
|
|
927
|
+
print("\n💡 Tip: Run 'npx synapse-hub welcome' (or 'npm start') to launch the visual landing page.")
|
|
519
928
|
sys.exit(0)
|
|
520
929
|
|
|
521
|
-
# Enforce
|
|
930
|
+
# Enforce canonical author attribution and anti-tamper provenance
|
|
522
931
|
from author_integrity import assert_integrity_or_raise
|
|
523
932
|
assert_integrity_or_raise()
|
|
524
933
|
|
|
934
|
+
if getattr(args, "quiet", False):
|
|
935
|
+
os.environ["SYNAPSE_QUIET"] = "1"
|
|
936
|
+
|
|
525
937
|
# Non-intrusive cached update notification (24h cache)
|
|
526
|
-
if args.subcommand not in ("update", "mcp-serve", "version"):
|
|
938
|
+
if args.subcommand not in ("update", "mcp-serve", "version") and not getattr(args, "quiet", False):
|
|
527
939
|
try:
|
|
528
940
|
import update_sentinel
|
|
529
941
|
update_sentinel.check_for_updates(force=False, notify=True)
|
|
530
|
-
except
|
|
942
|
+
except (ImportError, OSError, TimeoutError):
|
|
531
943
|
pass
|
|
532
944
|
|
|
533
945
|
# Dispatch subcommand
|