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.
Files changed (317) hide show
  1. package/.agents/agents/failure-analyst.md +11 -0
  2. package/.agents/agents/live-explorer.md +28 -0
  3. package/.agents/agents/orchestrator.md +20 -4
  4. package/.agents/agents/pom-crafter.md +12 -0
  5. package/.agents/agents/quality-gatekeeper.md +19 -4
  6. package/.agents/agents/test-runner.md +11 -0
  7. package/.agents/rules/communication-style.md +40 -0
  8. package/.agents/rules/context-engineering.md +23 -0
  9. package/.agents/rules/git-push-protocol.md +11 -17
  10. package/.agents/rules/graphify.md +14 -14
  11. package/.agents/rules/lessons-learned.md +3 -3
  12. package/.agents/rules/mandatory-playwright-live.md +29 -29
  13. package/.agents/rules/mobile_appium_rules.md +132 -0
  14. package/.agents/rules/performance_testing_rules.md +74 -0
  15. package/.agents/rules/skill-precedence.md +1 -1
  16. package/.agents/rules/systematic-debugging.md +6 -6
  17. package/.agents/skills/agent-orchestration-multi-agent-optimize/SKILL.md +64 -215
  18. package/.agents/skills/agent-orchestration-multi-agent-optimize/examples/swarm_workload_config.json +12 -0
  19. package/.agents/skills/antigravity-test-sentinel/SKILL.md +3 -3
  20. package/.agents/skills/antigravity-test-sentinel/examples/dod_gate_policy.json +11 -0
  21. package/.agents/skills/api-network-mocking-interception/SKILL.md +1 -1
  22. package/.agents/skills/api-network-mocking-interception/examples/network_route_stub.json +9 -0
  23. package/.agents/skills/api-spec-to-e2e-matrix/SKILL.md +9 -9
  24. package/.agents/skills/api-spec-to-e2e-matrix/examples/sample_openapi.json +19 -0
  25. package/.agents/skills/architecture-decision-records/SKILL.md +35 -412
  26. package/.agents/skills/architecture-decision-records/examples/0001-record-architecture-decisions.md +12 -0
  27. package/.agents/skills/auth-session-and-cookie-manager/SKILL.md +4 -1
  28. package/.agents/skills/auth-session-and-cookie-manager/examples/storage_state_sample.json +11 -0
  29. package/.agents/skills/backend-load-and-stress-patterns/SKILL.md +80 -186
  30. package/.agents/skills/backend-load-and-stress-patterns/examples/k6_load_test_sample.js +13 -0
  31. package/.agents/skills/bats-testing-patterns/SKILL.md +1 -1
  32. package/.agents/skills/bats-testing-patterns/examples/cli_runner_test.bats +6 -0
  33. package/.agents/skills/bats-testing-patterns/resources/implementation-playbook.md +614 -614
  34. package/.agents/skills/clean-pom-crafter/SKILL.md +21 -3
  35. package/.agents/skills/clean-pom-crafter/examples/standard_test_case.groovy +28 -28
  36. package/.agents/skills/clean-pom-crafter/references/pom_patterns.groovy +138 -138
  37. package/.agents/skills/code-refactoring-refactor-clean/SKILL.md +2 -2
  38. package/.agents/skills/code-refactoring-refactor-clean/examples/refactored_page_sample.groovy +9 -0
  39. package/.agents/skills/code-refactoring-refactor-clean/resources/implementation-playbook.md +9 -7
  40. package/.agents/skills/db-state-verifier-and-seeder/SKILL.md +5 -5
  41. package/.agents/skills/db-state-verifier-and-seeder/examples/db_fixture_seed.json +12 -0
  42. package/.agents/skills/e2e-testing-patterns/SKILL.md +1 -1
  43. package/.agents/skills/e2e-testing-patterns/examples/playwright_sharded_config.ts +12 -0
  44. package/.agents/skills/e2e-testing-patterns/resources/implementation-playbook.md +522 -522
  45. package/.agents/skills/failure-autopsy-and-healing/SKILL.md +17 -3
  46. package/.agents/skills/failure-autopsy-and-healing/examples/sample_junit_failure.xml +8 -0
  47. package/.agents/skills/failure-autopsy-and-healing/references/healing_matrix.md +64 -64
  48. package/.agents/skills/failure-autopsy-and-healing/references/qa_investigation_protocol.md +56 -56
  49. package/.agents/skills/failure-autopsy-and-healing/scripts/triage_failures.sh +98 -98
  50. package/.agents/skills/file-and-report-validator/SKILL.md +1 -1
  51. package/.agents/skills/file-and-report-validator/examples/sample_export_schema.json +14 -0
  52. package/.agents/skills/flaky-test-sentinel-and-quarantine/SKILL.md +3 -3
  53. package/.agents/skills/flaky-test-sentinel-and-quarantine/examples/quarantine_registry.json +11 -0
  54. package/.agents/skills/gherkin-to-suite/SKILL.md +103 -0
  55. package/.agents/skills/gherkin-to-suite/examples/checkout.feature +39 -0
  56. package/.agents/skills/gherkin-to-suite/examples/suite_report_sample.json +334 -0
  57. package/.agents/skills/github-actions-templates/SKILL.md +47 -304
  58. package/.agents/skills/github-actions-templates/examples/matrix_test_pipeline.yml +8 -0
  59. package/.agents/skills/graphify-impact-analyzer/SKILL.md +6 -6
  60. package/.agents/skills/graphify-impact-analyzer/examples/dependency_blast_radius.json +8 -0
  61. package/.agents/skills/katalon-cli-runner/SKILL.md +2 -2
  62. package/.agents/skills/katalon-cli-runner/examples/headless_kre_exec.sh +3 -0
  63. package/.agents/skills/katalon-cli-runner/references/groovy-patterns.md +209 -209
  64. package/.agents/skills/katalon-cli-runner/references/katalon-api.md +155 -155
  65. package/.agents/skills/katalon-cli-runner/references/runner_commands.md +67 -67
  66. package/.agents/skills/lam-script-generator/SKILL.md +42 -1
  67. package/.agents/skills/lam-script-generator/examples/user_story_sample.md +8 -0
  68. package/.agents/skills/lean-code-ladder/SKILL.md +83 -0
  69. package/.agents/skills/lean-code-ladder/examples/ladder_walkthrough.md +37 -0
  70. package/.agents/skills/meta-prompt-crafter/SKILL.md +107 -0
  71. package/.agents/skills/meta-prompt-crafter/examples/qa_prompt_template.md +35 -0
  72. package/.agents/skills/persistent-planning-files/SKILL.md +108 -0
  73. package/.agents/skills/persistent-planning-files/examples/task_plan_example.md +56 -0
  74. package/.agents/skills/playwright-live-interaction/SKILL.md +49 -1
  75. package/.agents/skills/playwright-live-interaction/examples/live_probe_script.js +5 -0
  76. package/.agents/skills/playwright-live-interaction/references/advanced_superpowers.md +160 -160
  77. package/.agents/skills/playwright-live-interaction/references/compact_accessibility_snapshots.md +75 -75
  78. package/.agents/skills/playwright-live-interaction/references/recipes.md +388 -388
  79. package/.agents/skills/playwright-live-interaction/references/swarm_orchestration.md +134 -134
  80. package/.agents/skills/playwright-webapp-testing/SKILL.md +93 -0
  81. package/.agents/skills/playwright-webapp-testing/examples/server_lifecycle_playwright.py +63 -0
  82. package/.agents/skills/rbt-manual-testing/SKILL.md +150 -0
  83. package/.agents/skills/rbt-manual-testing/examples/checkout_rbt_manual_suite.md +25 -0
  84. package/.agents/skills/security-dast-sentinel/SKILL.md +57 -135
  85. package/.agents/skills/security-dast-sentinel/examples/dast_scan_config.json +10 -0
  86. package/.agents/skills/self-healing-locator/SKILL.md +24 -10
  87. package/.agents/skills/self-healing-locator/examples/aom_diff_sample.json +16 -0
  88. package/.agents/skills/skillspector-security-guard/SKILL.md +32 -90
  89. package/.agents/skills/skillspector-security-guard/examples/safe_mcp_config.json +12 -0
  90. package/.agents/skills/surgical-coding-principles/SKILL.md +89 -0
  91. package/.agents/skills/surgical-coding-principles/examples/surgical_vs_scope_creep.md +46 -0
  92. package/.agents/skills/synthetic-test-data-generator/SKILL.md +3 -3
  93. package/.agents/skills/synthetic-test-data-generator/examples/idempotent_data_recipe.json +9 -0
  94. package/.agents/skills/systematic-debugging/SKILL.md +100 -0
  95. package/.agents/skills/systematic-debugging/examples/four_phase_case.md +44 -0
  96. package/.agents/skills/test-driven-development/SKILL.md +114 -0
  97. package/.agents/skills/test-driven-development/examples/red_green_refactor_qa.md +78 -0
  98. package/.agents/skills/token-and-context-optimizer/SKILL.md +1 -1
  99. package/.agents/skills/token-and-context-optimizer/examples/distilled_log_sample.txt +3 -0
  100. package/.agents/skills/verification-before-completion/SKILL.md +100 -0
  101. package/.agents/skills/verification-before-completion/examples/evidence_log_example.md +46 -0
  102. package/.agents/skills/visual-regression-sentinel/SKILL.md +21 -1
  103. package/.agents/skills/visual-regression-sentinel/examples/visual_mask_rules.json +9 -0
  104. package/.agents/skills/wcag-audit-patterns/SKILL.md +3 -3
  105. package/.agents/skills/wcag-audit-patterns/examples/wcag_compliance_checklist.json +10 -0
  106. package/.agents/skills/wcag-audit-patterns/resources/implementation-playbook.md +541 -541
  107. package/.agents/skills/web-vitals-and-performance-profiler/SKILL.md +1 -1
  108. package/.agents/skills/web-vitals-and-performance-profiler/examples/cwv_budget_policy.json +6 -0
  109. package/.agents/templates/completion_report.md +57 -57
  110. package/.agents/workflows/analyze_requirement_document.md +18 -0
  111. package/.agents/workflows/export_testcases_excel.md +32 -0
  112. package/.agents/workflows/generate_combinatorial_test_data.md +28 -0
  113. package/.agents/workflows/generate_cross_module_test_plan.md +37 -0
  114. package/.agents/workflows/generate_manual_testcases_rbt.md +56 -0
  115. package/.agents/workflows/generate_requirements_from_website.md +25 -0
  116. package/.agents/workflows/generate_testcases_from_requirements.md +21 -0
  117. package/.agents/workflows/graphify.md +10 -10
  118. package/.agents/workflows/verify.md +2 -2
  119. package/.cursor/rules/language.mdc +7 -7
  120. package/.cursor/rules/synapse-qa.mdc +23 -0
  121. package/.cursorrules +7 -0
  122. package/.pre-commit-hooks.yaml +14 -0
  123. package/.windsurfrules +7 -0
  124. package/AGENTS.md +54 -15
  125. package/CLAUDE.md +35 -12
  126. package/LICENSE +30 -0
  127. package/NOTICE +180 -0
  128. package/README.en.md +325 -0
  129. package/README.md +247 -512
  130. package/action.yml +51 -0
  131. package/benchmarks/qa_eval/README.md +71 -0
  132. package/benchmarks/qa_eval/build_dataset.py +677 -0
  133. package/benchmarks/qa_eval/dataset/api_contract_drift/qa-challenge-06_api_contract_drift.json +22 -0
  134. package/benchmarks/qa_eval/dataset/api_contract_drift/qa-challenge-07_api_contract_drift.json +22 -0
  135. package/benchmarks/qa_eval/dataset/api_contract_drift/qa-challenge-08_api_contract_drift.json +22 -0
  136. package/benchmarks/qa_eval/dataset/api_contract_drift/qa-challenge-09_api_contract_drift.json +22 -0
  137. package/benchmarks/qa_eval/dataset/api_contract_drift/qa-challenge-10_api_contract_drift.json +22 -0
  138. package/benchmarks/qa_eval/dataset/fake_pass_tautology/qa-challenge-21_fake_pass_tautology.json +21 -0
  139. package/benchmarks/qa_eval/dataset/fake_pass_tautology/qa-challenge-22_fake_pass_tautology.json +21 -0
  140. package/benchmarks/qa_eval/dataset/fake_pass_tautology/qa-challenge-23_fake_pass_tautology.json +21 -0
  141. package/benchmarks/qa_eval/dataset/fake_pass_tautology/qa-challenge-24_fake_pass_tautology.json +21 -0
  142. package/benchmarks/qa_eval/dataset/fake_pass_tautology/qa-challenge-25_fake_pass_tautology.json +21 -0
  143. package/benchmarks/qa_eval/dataset/locator_drift/qa-challenge-01_locator_drift.json +23 -0
  144. package/benchmarks/qa_eval/dataset/locator_drift/qa-challenge-02_locator_drift.json +23 -0
  145. package/benchmarks/qa_eval/dataset/locator_drift/qa-challenge-03_locator_drift.json +23 -0
  146. package/benchmarks/qa_eval/dataset/locator_drift/qa-challenge-04_locator_drift.json +23 -0
  147. package/benchmarks/qa_eval/dataset/locator_drift/qa-challenge-05_locator_drift.json +23 -0
  148. package/benchmarks/qa_eval/dataset/stale_and_mutation/qa-challenge-16_stale_and_mutation.json +22 -0
  149. package/benchmarks/qa_eval/dataset/stale_and_mutation/qa-challenge-17_stale_and_mutation.json +22 -0
  150. package/benchmarks/qa_eval/dataset/stale_and_mutation/qa-challenge-18_stale_and_mutation.json +22 -0
  151. package/benchmarks/qa_eval/dataset/stale_and_mutation/qa-challenge-19_stale_and_mutation.json +22 -0
  152. package/benchmarks/qa_eval/dataset/stale_and_mutation/qa-challenge-20_stale_and_mutation.json +23 -0
  153. package/benchmarks/qa_eval/dataset/timing_and_race/qa-challenge-11_timing_and_race.json +22 -0
  154. package/benchmarks/qa_eval/dataset/timing_and_race/qa-challenge-12_timing_and_race.json +22 -0
  155. package/benchmarks/qa_eval/dataset/timing_and_race/qa-challenge-13_timing_and_race.json +22 -0
  156. package/benchmarks/qa_eval/dataset/timing_and_race/qa-challenge-14_timing_and_race.json +22 -0
  157. package/benchmarks/qa_eval/dataset/timing_and_race/qa-challenge-15_timing_and_race.json +22 -0
  158. package/benchmarks/qa_eval/eval_runner.py +418 -0
  159. package/benchmarks/qa_eval/reports/AB_METHODOLOGY_REPORT.md +83 -0
  160. package/benchmarks/qa_eval/reports/BENCHMARK_REPORT.md +69 -0
  161. package/benchmarks/qa_eval/reports/eval_results.json +105 -0
  162. package/bin/agent-qa.js +10 -3
  163. package/docs/ARCHITECTURE.md +107 -0
  164. package/docs/CI_CD_INTEGRATION.md +94 -0
  165. package/docs/CLI_REFERENCE.md +157 -0
  166. package/docs/CONTRIBUTING.md +91 -0
  167. package/docs/PLUGIN_DEVELOPMENT_GUIDE.md +126 -0
  168. package/docs/TOKEN_QUOTA_PLAYBOOK.md +41 -0
  169. package/docs/adopted-ecosystem-tools.md +87 -0
  170. package/docs/schemas/synapse.config.schema.json +64 -0
  171. package/examples/cypress-ecommerce-suite/README.md +45 -0
  172. package/examples/cypress-ecommerce-suite/cypress/e2e/checkout.cy.js +17 -0
  173. package/examples/cypress-ecommerce-suite/cypress/pages/BasePage.js +29 -0
  174. package/examples/cypress-ecommerce-suite/cypress/pages/CartPage.js +51 -0
  175. package/examples/cypress-ecommerce-suite/cypress.config.js +13 -0
  176. package/examples/cypress-ecommerce-suite/package.json +13 -0
  177. package/examples/katalon-suite/Keywords/pages/BasePage.groovy +19 -0
  178. package/examples/katalon-suite/Keywords/pages/DashboardPage.groovy +29 -0
  179. package/examples/katalon-suite/Keywords/pages/LoginPage.groovy +45 -0
  180. package/examples/katalon-suite/Profiles/default.glbl +12 -0
  181. package/examples/katalon-suite/README.md +18 -0
  182. package/examples/katalon-suite/Scripts/Auth/TC_LoginSuccess/Script1234567890.groovy +12 -0
  183. package/examples/katalon-suite/Scripts/Dashboard/TC_ViewSummary/Script1234567891.groovy +15 -0
  184. package/examples/katalon-suite/katalon_suite.prj +21 -0
  185. package/examples/playwright-crm-suite/README.md +40 -0
  186. package/examples/playwright-crm-suite/package.json +14 -0
  187. package/examples/playwright-crm-suite/pages/BasePage.ts +37 -0
  188. package/examples/playwright-crm-suite/pages/CustomerPage.ts +57 -0
  189. package/examples/playwright-crm-suite/pages/LoginPage.ts +32 -0
  190. package/examples/playwright-crm-suite/playwright.config.ts +27 -0
  191. package/examples/playwright-crm-suite/tests/auth.spec.ts +22 -0
  192. package/examples/playwright-crm-suite/tests/customers.spec.ts +33 -0
  193. package/examples/plugins/sample-custom-plugin/README.md +14 -0
  194. package/examples/plugins/sample-custom-plugin/plugin.json +16 -0
  195. package/examples/plugins/sample-custom-plugin/skills/custom-security-headers-audit/SKILL.md +29 -0
  196. package/examples/plugins/sample-custom-plugin/skills/custom-security-headers-audit/examples/audit_fixture.json +8 -0
  197. package/examples/plugins/sample-custom-plugin/tools/custom_security_headers.py +125 -0
  198. package/examples/practices/README.md +22 -0
  199. package/examples/practices/requirements/crm/requirements_contracts.md +292 -0
  200. package/examples/practices/requirements/crm/requirements_customers.md +462 -0
  201. package/examples/practices/requirements/crm/requirements_login.md +202 -0
  202. package/examples/practices/requirements/crm/requirements_projects.md +396 -0
  203. package/examples/practices/requirements/crm/requirements_tasks.md +343 -0
  204. package/examples/practices/requirements/ecommerce/requirements_category_brand.txt +402 -0
  205. package/examples/practices/requirements/jira/KAN-5/KAN-1/2026-04-03_04-28-27.png +0 -0
  206. package/examples/practices/requirements/jira/KAN-5/KAN-1/KAN-1_requirement.md +52 -0
  207. package/examples/practices/requirements/jira/KAN-5/KAN-4/2026-04-03_04-28-19.png +0 -0
  208. package/examples/practices/requirements/jira/KAN-5/KAN-4/2026-04-03_04-28-57.png +0 -0
  209. package/examples/practices/requirements/jira/KAN-5/KAN-4/KAN-4_requirement.md +119 -0
  210. package/examples/practices/requirements/jira/KAN-5/KAN-5_overview.md +9 -0
  211. package/examples/practices/requirements/jira/KAN-5/KAN-6/2026-04-03_05-58-08.png +0 -0
  212. package/examples/practices/requirements/jira/KAN-5/KAN-6/2026-04-03_05-58-23.png +0 -0
  213. package/examples/practices/requirements/jira/KAN-5/KAN-6/KAN-6_requirement.md +32 -0
  214. package/examples/practices/testcases/api/book_management_api_test_cases.md +144 -0
  215. package/examples/practices/testcases/api/user_management_api_test_cases.md +139 -0
  216. package/examples/practices/testcases/crm/test_cases_crm_login.md +148 -0
  217. package/examples/practices/testcases/crm/test_cases_customers.md +156 -0
  218. package/examples/pytest-api-suite/README.md +45 -0
  219. package/examples/pytest-api-suite/conftest.py +31 -0
  220. package/examples/pytest-api-suite/pages/user_api_client.py +36 -0
  221. package/examples/pytest-api-suite/requirements.txt +2 -0
  222. package/examples/pytest-api-suite/tests/test_user_api.py +44 -0
  223. package/examples/selenium-suite/README.md +18 -0
  224. package/examples/selenium-suite/pages/base_page.py +27 -0
  225. package/examples/selenium-suite/pages/login_page.py +29 -0
  226. package/examples/selenium-suite/pages/order_page.py +25 -0
  227. package/examples/selenium-suite/pytest.ini +6 -0
  228. package/examples/selenium-suite/requirements.txt +2 -0
  229. package/examples/selenium-suite/tests/test_login.py +10 -0
  230. package/examples/selenium-suite/tests/test_order.py +10 -0
  231. package/package.json +22 -7
  232. package/scripts/generate_skill_examples.py +244 -0
  233. package/scripts/install.ps1 +112 -0
  234. package/scripts/install_global_plugin.ps1 +94 -0
  235. package/scripts/install_global_plugin.sh +49 -0
  236. package/scripts/lint_skills.ps1 +57 -0
  237. package/scripts/package_dist.py +323 -0
  238. package/scripts/setup.sh +59 -0
  239. package/scripts/update_hub.ps1 +19 -0
  240. package/scripts/update_hub.sh +15 -0
  241. package/skills_manifest.json +209 -6
  242. package/synapse.config.json +30 -0
  243. package/templates/PROJECT_AI_GUIDE_TEMPLATE.md +7 -7
  244. package/templates/PROJECT_STATE_TEMPLATE.md +1 -1
  245. package/templates/ai_bridges/CLAUDE.md +33 -16
  246. package/templates/ai_bridges/copilot-instructions.md +14 -21
  247. package/templates/ai_bridges/cursor_synapse_qa.mdc +17 -20
  248. package/templates/ai_bridges/windsurfrules +21 -21
  249. package/templates/ci/github-actions-synapse.yml +71 -4
  250. package/templates/welcome.html.tmpl +1674 -0
  251. package/tools/.infer_baseline.json +1102 -0
  252. package/tools/TOOLS_RUNBOOK.md +92 -130
  253. package/tools/__init__.py +26 -0
  254. package/tools/agent_canary.py +501 -501
  255. package/tools/analyze_project.py +31 -17
  256. package/tools/api_fuzzer.py +278 -6
  257. package/tools/author_integrity.py +6 -6
  258. package/tools/auto_heal.py +1 -1
  259. package/tools/browser_helpers.js +105 -7
  260. package/tools/bug_reporter.py +31 -1
  261. package/tools/bump_version.py +23 -3
  262. package/tools/cache_resolver.py +248 -14
  263. package/tools/check_env.py +55 -14
  264. package/tools/check_version_sync.py +153 -0
  265. package/tools/ci_healing_hook.py +1 -1
  266. package/tools/cli.py +263 -13
  267. package/tools/count_tokens.py +1257 -0
  268. package/tools/dashboard_generator.py +2638 -0
  269. package/tools/db_sandbox.py +198 -20
  270. package/tools/e2e_flow_prober.ps1 +12 -64
  271. package/tools/e2e_flow_prober.py +99 -0
  272. package/tools/e2e_flow_prober.sh +4 -0
  273. package/tools/export_postman_collection.py +29 -7
  274. package/tools/flaky_detector.py +4 -3
  275. package/tools/generate_allure_report.ps1 +12 -29
  276. package/tools/generate_allure_report.py +77 -0
  277. package/tools/generate_allure_report.sh +4 -0
  278. package/tools/generate_jmx_plan.py +299 -68
  279. package/tools/generate_test_reports.ps1 +12 -134
  280. package/tools/generate_test_reports.py +133 -0
  281. package/tools/generate_test_reports.sh +4 -0
  282. package/tools/gherkin_suite.py +758 -0
  283. package/tools/git_pre_commit_guard.py +12 -6
  284. package/tools/goldfish_review.py +366 -0
  285. package/tools/heal_pr_automator.py +1 -1
  286. package/tools/heuristic_locator_matcher.py +170 -21
  287. package/tools/infer_linter.py +612 -70
  288. package/tools/jtl_analyzer.py +1 -1
  289. package/tools/lint_ai_docs.py +64 -0
  290. package/tools/matrix_sharder.py +1 -1
  291. package/tools/mcp_excel_server.ps1 +12 -250
  292. package/tools/mcp_excel_server.py +249 -0
  293. package/tools/mcp_excel_server.sh +4 -0
  294. package/tools/mcp_server.py +368 -144
  295. package/tools/md_to_xlsx.py +307 -0
  296. package/tools/micro_mutator.py +300 -69
  297. package/tools/omni_transpiler.py +2 -2
  298. package/tools/output_formatter.py +128 -0
  299. package/tools/pinpoint_failure.py +88 -88
  300. package/tools/project_state.py +2 -2
  301. package/tools/repo_map.py +1 -1
  302. package/tools/safety_firewall.py +197 -33
  303. package/tools/setup_project.py +294 -30
  304. package/tools/skillspector.py +8 -8
  305. package/tools/spec_drift_sentinel.py +439 -0
  306. package/tools/sync_agent_rules.py +248 -0
  307. package/tools/telemetry_correlator.py +45 -0
  308. package/tools/test_impact.py +51 -12
  309. package/tools/tms_sync_bridge.py +21 -5
  310. package/tools/universal_ir.py +3 -0
  311. package/tools/update_sentinel.py +87 -15
  312. package/tools/verify_all.ps1 +13 -0
  313. package/tools/verify_all.py +463 -79
  314. package/tools/visual_diff_canvas.py +1 -0
  315. package/tools/visual_som_helper.py +1 -1
  316. package/tools/watch_mode.py +305 -0
  317. package/tools/welcome_page.py +291 -0
@@ -20,6 +20,7 @@ Automated actions:
20
20
 
21
21
  import os
22
22
  import sys
23
+ import json
23
24
  import shutil
24
25
  import argparse
25
26
  from pathlib import Path
@@ -95,7 +96,7 @@ def detect_tech_stack(target_dir):
95
96
  "language": "Groovy",
96
97
  "page_dir": "Keywords/pages",
97
98
  "test_dir": "Scripts",
98
- "run_cmd": "./tools/run_headless_kre.sh (or katalonc CLI)"
99
+ "run_cmd": "katalonc -noSplash -runMode=console"
99
100
  }
100
101
 
101
102
  # 2. Playwright check
@@ -121,7 +122,21 @@ def detect_tech_stack(target_dir):
121
122
  "run_cmd": "npx cypress run --headless"
122
123
  }
123
124
 
124
- # 4. Pytest check
125
+ # 4. Selenium WebDriver check
126
+ req_txt = target_path / "requirements.txt"
127
+ has_selenium_req = req_txt.exists() and "selenium" in req_txt.read_text(encoding="utf-8", errors="ignore").lower()
128
+ has_selenium_code = any("selenium" in f.read_text(encoding="utf-8", errors="ignore") for f in list(target_path.glob("**/*.py"))[:10]) if list(target_path.glob("**/*.py")) else False
129
+ if has_selenium_req or has_selenium_code:
130
+ return {
131
+ "name": target_path.name,
132
+ "framework": "Selenium WebDriver",
133
+ "language": "Python",
134
+ "page_dir": "pages",
135
+ "test_dir": "tests",
136
+ "run_cmd": "pytest tests/ -v"
137
+ }
138
+
139
+ # 5. Pytest check
125
140
  if (target_path / "pytest.ini").exists() or list(target_path.glob("test_*.py")):
126
141
  return {
127
142
  "name": target_path.name,
@@ -143,7 +158,7 @@ def detect_tech_stack(target_dir):
143
158
  }
144
159
 
145
160
 
146
- def ensure_project_ai_guide(target_dir, stack_info):
161
+ def ensure_project_ai_guide(target_dir, stack_info, profile="full"):
147
162
  """Generates PROJECT_AI_GUIDE.md tailored to the target project if missing."""
148
163
  guide_path = os.path.join(target_dir, "PROJECT_AI_GUIDE.md")
149
164
  if os.path.exists(guide_path):
@@ -167,6 +182,14 @@ def ensure_project_ai_guide(target_dir, stack_info):
167
182
  content = content.replace("tests/e2e/... or Scripts/...", stack_info["test_dir"])
168
183
  content = content.replace("[e.g., npx playwright test --project=chromium --reporter=html,junit:results.xml]", stack_info["run_cmd"])
169
184
 
185
+ profile_line = f"- **Active Skills Profile:** `{profile.upper()}`"
186
+ if profile_line not in content:
187
+ lang_target = f"- **Script Language:** `{stack_info['language']}`"
188
+ if lang_target in content:
189
+ content = content.replace(lang_target, f"{lang_target}\n{profile_line}")
190
+ else:
191
+ content = content.replace("## 1. General System Under Test", f"## 1. General System Under Test\n{profile_line}")
192
+
170
193
  with open(guide_path, "w", encoding="utf-8") as f:
171
194
  f.write(content)
172
195
 
@@ -195,7 +218,7 @@ def install_git_pre_push_hook(target_dir):
195
218
  try:
196
219
  with open(manifest_file, "r", encoding="utf-8") as f:
197
220
  pkg_ver = json.load(f).get("version", pkg_ver)
198
- except Exception:
221
+ except (IOError, json.JSONDecodeError, KeyError):
199
222
  pass
200
223
 
201
224
  verify_all_script = os.path.join(SCRIPT_DIR, "verify_all.py").replace("\\", "/")
@@ -204,22 +227,31 @@ def install_git_pre_push_hook(target_dir):
204
227
  hook_snippet = f"""
205
228
  # --- Synapse-Hub Pre-Push Quality Gate (v{pkg_ver}) ---
206
229
  echo "\\n[AI-GUARD] Running Pre-Push Verification (Quality Gates DoD)..."
207
- if command -v npx >/dev/null 2>&1; then
208
- npx synapse-hub@{pkg_ver} verify || npx synapse-hub verify
209
- elif [ -f "{verify_all_script}" ]; then
230
+ # Prioritize local tool execution to run offline without network latency or registry dependency
231
+ if [ -f "{verify_all_script}" ]; then
210
232
  python3 "{verify_all_script}" || python "{verify_all_script}"
233
+ elif command -v synapse-hub >/dev/null 2>&1; then
234
+ synapse-hub verify
235
+ elif command -v agent-qa >/dev/null 2>&1; then
236
+ agent-qa verify
237
+ elif command -v npx >/dev/null 2>&1; then
238
+ npx --no-install synapse-hub verify 2>/dev/null || npx synapse-hub@{pkg_ver} verify
211
239
  fi
212
240
  if [ $? -ne 0 ]; then
213
241
  echo "\\n[AI-GUARD - REJECTED] Git Push aborted: Quality Gates verification failed!"
214
- echo "Please fix defects or run 'npx synapse-hub@{pkg_ver} verify' locally before pushing.\\n"
242
+ echo "Please fix defects or run 'python tools/verify_all.py' locally before pushing.\\n"
215
243
  exit 1
216
244
  fi
217
245
 
218
246
  echo "[AI-GUARD - PASSED] Quality Gates satisfied. Syncing project health report..."
219
- if command -v npx >/dev/null 2>&1; then
220
- npx synapse-hub@{pkg_ver} analyze || npx synapse-hub analyze
221
- elif [ -f "{analyze_script}" ]; then
247
+ if [ -f "{analyze_script}" ]; then
222
248
  python3 "{analyze_script}" || python "{analyze_script}"
249
+ elif command -v synapse-hub >/dev/null 2>&1; then
250
+ synapse-hub analyze
251
+ elif command -v agent-qa >/dev/null 2>&1; then
252
+ agent-qa analyze
253
+ elif command -v npx >/dev/null 2>&1; then
254
+ npx --no-install synapse-hub analyze 2>/dev/null || npx synapse-hub@{pkg_ver} analyze
223
255
  fi
224
256
  echo "[AI-GUARD - READY] Pushing to remote...\\n"
225
257
  # --- End Synapse-Hub Quality Gate ---
@@ -250,7 +282,7 @@ echo "[AI-GUARD - READY] Pushing to remote...\\n"
250
282
  # Attempt to make executable on Unix-like environments
251
283
  try:
252
284
  os.chmod(hook_file, 0o755)
253
- except Exception:
285
+ except OSError:
254
286
  pass
255
287
 
256
288
  print(f" {GREEN}[OK] Configured automated Pre-Push Git Hook:{RESET} {hook_file} (pinned to v{pkg_ver})")
@@ -260,6 +292,82 @@ echo "[AI-GUARD - READY] Pushing to remote...\\n"
260
292
  return False
261
293
 
262
294
 
295
+ def ensure_gitignore_protection(target_dir):
296
+ """Ensures local cache and generated AST intelligence artifacts are ignored in target repo."""
297
+ gitignore_path = os.path.join(target_dir, ".gitignore")
298
+ entries = [".synapse/", "repo_map.txt", "repo_map.json"]
299
+ try:
300
+ existing = ""
301
+ if os.path.exists(gitignore_path):
302
+ with open(gitignore_path, "r", encoding="utf-8", errors="ignore") as f:
303
+ existing = f.read()
304
+ missing = [e for e in entries if e not in existing]
305
+ if missing:
306
+ with open(gitignore_path, "a", encoding="utf-8") as f:
307
+ if existing and not existing.endswith("\n"):
308
+ f.write("\n")
309
+ f.write("\n# Synapse-Hub Local Cache & AST Intelligence\n")
310
+ for e in missing:
311
+ f.write(f"{e}\n")
312
+ print(f" {GREEN}[OK] Protected local cache in .gitignore:{RESET} {gitignore_path}")
313
+ return True
314
+ except OSError:
315
+ pass
316
+ return False
317
+
318
+
319
+ def install_git_post_merge_hook(target_dir):
320
+ """
321
+ Installs or appends an automated post-merge hook into target project's .git repository.
322
+ When a developer pulls code for the first time via 'git pull', this triggers the
323
+ welcome landing page once, then silently records it as completed.
324
+ """
325
+ git_dir = os.path.join(target_dir, ".git")
326
+ if not os.path.isdir(git_dir):
327
+ return False
328
+
329
+ hooks_dir = os.path.join(git_dir, "hooks")
330
+ os.makedirs(hooks_dir, exist_ok=True)
331
+ hook_file = os.path.join(hooks_dir, "post-merge")
332
+
333
+ welcome_script = os.path.join(SCRIPT_DIR, "welcome_page.py").replace("\\", "/")
334
+
335
+ hook_snippet = f"""# --- Synapse-Hub Post-Merge First-Pull Sentinel ---
336
+ # Security invariant: Never execute relative scripts from target repository
337
+ if [ -f "{welcome_script}" ]; then
338
+ python3 "{welcome_script}" --first-run 2>/dev/null || python "{welcome_script}" --first-run 2>/dev/null || true
339
+ elif command -v synapse-hub >/dev/null 2>&1; then
340
+ synapse-hub welcome --first-run 2>/dev/null || true
341
+ elif command -v agent-qa >/dev/null 2>&1; then
342
+ agent-qa welcome --first-run 2>/dev/null || true
343
+ fi
344
+ """
345
+ try:
346
+ if os.path.exists(hook_file):
347
+ with open(hook_file, "r", encoding="utf-8", errors="ignore") as f:
348
+ existing_content = f.read()
349
+
350
+ if "Synapse-Hub Post-Merge" in existing_content:
351
+ return True
352
+
353
+ final_content = existing_content.rstrip() + "\n" + hook_snippet
354
+ else:
355
+ final_content = "#!/bin/sh\n" + hook_snippet
356
+
357
+ with open(hook_file, "w", encoding="utf-8", newline="\n") as f:
358
+ f.write(final_content)
359
+
360
+ try:
361
+ os.chmod(hook_file, 0o755)
362
+ except OSError:
363
+ pass
364
+
365
+ print(f" {GREEN}[OK] Configured Post-Merge First-Pull Git Hook:{RESET} {hook_file}")
366
+ return True
367
+ except (OSError, UnicodeDecodeError):
368
+ return False
369
+
370
+
263
371
  def inject_antigravity_global_plugin():
264
372
  """
265
373
  Automatically injects Synapse-Hub into Antigravity's Global Plugin Directory
@@ -295,7 +403,7 @@ def inject_antigravity_global_plugin():
295
403
  if os.path.islink(dst):
296
404
  try:
297
405
  os.unlink(dst)
298
- except Exception:
406
+ except OSError:
299
407
  pass
300
408
  if sys.platform == "win32":
301
409
  try:
@@ -303,7 +411,7 @@ def inject_antigravity_global_plugin():
303
411
  if not os.path.exists(dst):
304
412
  _winapi.CreateJunction(src, dst)
305
413
  return
306
- except Exception:
414
+ except (OSError, ImportError, AttributeError):
307
415
  pass
308
416
  shutil.copytree(src, dst, dirs_exist_ok=True, ignore=shutil.ignore_patterns("__pycache__", "*.pyc", "*.tmp"))
309
417
 
@@ -405,7 +513,65 @@ def install_universal_ai_bridges(target_dir):
405
513
  return True
406
514
 
407
515
 
408
- def run_setup(target_repo):
516
+ def uninstall_setup(target_repo: str) -> int:
517
+ """Safely reverts and removes files installed by setup_project in the target repo."""
518
+ print(f"\n{BOLD}{YELLOW}======================================================================{RESET}")
519
+ print(f"{BOLD}{YELLOW} SYNAPSE HUB — REVERT & UNINSTALL SETUP {RESET}")
520
+ print(f"{BOLD}{YELLOW}======================================================================{RESET}")
521
+ print(f"Target Repository: {target_repo}")
522
+
523
+ reverted_items = 0
524
+
525
+ # 1. Remove PROJECT_AI_GUIDE.md
526
+ guide_file = os.path.join(target_repo, "PROJECT_AI_GUIDE.md")
527
+ if os.path.exists(guide_file):
528
+ os.remove(guide_file)
529
+ print(f" {GREEN}[REMOVED]{RESET} {guide_file}")
530
+ reverted_items += 1
531
+
532
+ # 2. Restore/Remove Git Pre-Push Hook
533
+ hook_file = os.path.join(target_repo, ".git", "hooks", "pre-push")
534
+ backup_file = os.path.join(target_repo, ".git", "hooks", "pre-push.bak")
535
+ if os.path.exists(backup_file):
536
+ if os.path.exists(hook_file):
537
+ os.remove(hook_file)
538
+ shutil.move(backup_file, hook_file)
539
+ print(f" {GREEN}[RESTORED]{RESET} Restored original pre-push hook from backup")
540
+ reverted_items += 1
541
+ elif os.path.exists(hook_file):
542
+ with open(hook_file, "r", encoding="utf-8", errors="ignore") as f:
543
+ content = f.read()
544
+ if "Synapse-Hub" in content or "synapse-hub" in content:
545
+ os.remove(hook_file)
546
+ print(f" {GREEN}[REMOVED]{RESET} Cleaned Synapse-Hub pre-push hook")
547
+ reverted_items += 1
548
+
549
+ # 3. Remove Cursor rule
550
+ cursor_rule = os.path.join(target_repo, ".cursor", "rules", "synapse-qa.mdc")
551
+ if os.path.exists(cursor_rule):
552
+ os.remove(cursor_rule)
553
+ print(f" {GREEN}[REMOVED]{RESET} {cursor_rule}")
554
+ reverted_items += 1
555
+
556
+ # 4. Remove Copilot instruction
557
+ copilot_file = os.path.join(target_repo, ".github", "copilot-instructions.md")
558
+ if os.path.exists(copilot_file):
559
+ os.remove(copilot_file)
560
+ print(f" {GREEN}[REMOVED]{RESET} {copilot_file}")
561
+ reverted_items += 1
562
+
563
+ # 5. Remove Windsurf rules
564
+ windsurf_file = os.path.join(target_repo, ".windsurfrules")
565
+ if os.path.exists(windsurf_file):
566
+ os.remove(windsurf_file)
567
+ print(f" {GREEN}[REMOVED]{RESET} {windsurf_file}")
568
+ reverted_items += 1
569
+
570
+ print(f"\n{GREEN}✅ Uninstall complete! Cleaned {reverted_items} configuration files/hooks.{RESET}\n")
571
+ return 0
572
+
573
+
574
+ def run_setup(target_repo, dry_run=False, profile="auto", no_global=True, no_git_hook=False, no_browser=True, open_browser=False):
409
575
  """Main execution entrypoint for automated project setup."""
410
576
  print(f"\n{BOLD}{CYAN}======================================================================{RESET}")
411
577
  print(f"{BOLD}{CYAN} AUTONOMOUS ZERO-COMMAND PROJECT BOOTSTRAP (AI-READY SETUP) {RESET}")
@@ -417,9 +583,42 @@ def run_setup(target_repo):
417
583
  print(f"🔍 Detected Stack : {BOLD}{stack_info['framework']}{RESET} ({stack_info['language']})")
418
584
  print(f"📂 Structure Scope : Pages: `{stack_info['page_dir']}` | Tests: `{stack_info['test_dir']}`\n")
419
585
 
586
+ # Resolve active profile
587
+ if profile == "auto":
588
+ fw = stack_info.get("framework", "").lower()
589
+ lang = stack_info.get("language", "").lower()
590
+ if "playwright" in fw:
591
+ profile = "playwright"
592
+ elif "selenium" in fw:
593
+ profile = "selenium"
594
+ elif "cypress" in fw:
595
+ profile = "cypress"
596
+ elif "katalon" in fw:
597
+ profile = "katalon"
598
+ elif "pytest" in fw or "python" in lang:
599
+ profile = "pytest"
600
+ else:
601
+ profile = "full"
602
+
603
+ print(f"🎯 Selected Profile: {BOLD}{profile.upper()}{RESET}")
604
+ if dry_run:
605
+ print(f"Operational Mode : {YELLOW}DRY-RUN (Simulating without modifying files on disk){RESET}\n")
606
+ else:
607
+ print(f"Operational Mode : APPLY CHANGES\n")
608
+
609
+ if dry_run:
610
+ print(f"{YELLOW}[DRY-RUN PREVIEW]{RESET}")
611
+ print(f" • Profile: {profile.upper()}")
612
+ print(f" • Would generate: {os.path.join(target_repo, 'PROJECT_AI_GUIDE.md')}")
613
+ print(f" • Would deploy AI bridges: .cursor/rules/synapse-qa.mdc, .github/copilot-instructions.md, .windsurfrules")
614
+ print(f" • Would install pre-push hook: {os.path.join(target_repo, '.git', 'hooks', 'pre-push')}")
615
+ print(f" • Would initialize: Central Agent Memory (~/.agent_memory/global_cache.db)")
616
+ print(f"\n{GREEN}✅ Dry-run completed successfully. Zero changes written to disk.{RESET}\n")
617
+ return 0
618
+
420
619
  # 2. Ensure PROJECT_AI_GUIDE.md & PROJECT_STATE.md
421
620
  print(f"{BOLD}[1/5] Checking Project AI Guide & State Anchor...{RESET}")
422
- guide_created = ensure_project_ai_guide(target_repo, stack_info)
621
+ guide_created = ensure_project_ai_guide(target_repo, stack_info, profile=profile)
423
622
  project_state.init_state(target_repo)
424
623
 
425
624
  # 3. Deploy Universal AI Bridges (Cursor, Claude Code, GitHub Copilot, Windsurf)
@@ -427,35 +626,66 @@ def run_setup(target_repo):
427
626
  bridges_deployed = install_universal_ai_bridges(target_repo)
428
627
 
429
628
  # 4. Inject Antigravity Global Plugin
430
- print(f"\n{BOLD}[3/5] Injecting Antigravity Global Plugin (~/.gemini/config/plugins)...{RESET}")
431
- plugin_injected = inject_antigravity_global_plugin()
432
-
433
- # 4.1 Initialize Central Agent Memory (SQLite Cache)
434
- try:
435
- import cache_resolver
436
- cache_resolver.init_db(seed=True)
437
- print(f" {GREEN}[OK] Initialized Central Agent Memory (SQLite):{RESET} ~/.agent_memory/global_cache.db")
438
- except Exception as e:
439
- print(f" ⚠️ Could not initialize memory cache: {e}")
629
+ plugin_injected = False
630
+ if no_global:
631
+ print(f"\n{BOLD}[3/5] Checking Antigravity Global Plugin (~/.gemini/config/plugins)...{RESET}")
632
+ print(f" {YELLOW}[SKIP] Local-only mode (default). Skipped global plugin injection (pass --global to install globally).{RESET}")
633
+ else:
634
+ print(f"\n{BOLD}[3/5] Injecting Antigravity Global Plugin (~/.gemini/config/plugins)...{RESET}")
635
+ plugin_injected = inject_antigravity_global_plugin()
440
636
 
441
- # 5. Install Pre-Push Git Hook
442
- print(f"\n{BOLD}[4/5] Installing Zero-Leakage Git Pre-Push Hook...{RESET}")
443
- hook_installed = install_git_pre_push_hook(target_repo)
637
+ # 4.1 Initialize Central Agent Memory (SQLite Cache)
638
+ try:
639
+ import cache_resolver
640
+ cache_resolver.init_db(seed=True)
641
+ print(f" {GREEN}[OK] Initialized Central Agent Memory (SQLite):{RESET} ~/.agent_memory/global_cache.db")
642
+ except Exception as e:
643
+ print(f" ⚠️ Could not initialize memory cache: {e}")
644
+
645
+ # 4.2 Protect local cache in .gitignore
646
+ ensure_gitignore_protection(target_repo)
647
+
648
+ # 5. Install Pre-Push & Post-Merge Git Hooks
649
+ hook_installed = False
650
+ if no_git_hook:
651
+ print(f"\n{BOLD}[4/5] Installing Zero-Leakage Git Hooks...{RESET}")
652
+ print(f" {YELLOW}[SKIP] Skipped Git hook installation (--no-git-hook).{RESET}")
653
+ else:
654
+ print(f"\n{BOLD}[4/5] Installing Zero-Leakage Git Hooks...{RESET}")
655
+ hook_installed = install_git_pre_push_hook(target_repo)
656
+ install_git_post_merge_hook(target_repo)
444
657
 
445
658
  # 6. Run 5-in-1 Comprehensive Health & AST Analysis
446
659
  print(f"\n{BOLD}[5/5] Executing Initial Health Audit & AST Mapping...{RESET}")
447
660
  analysis_code = analyze_project.run_full_analysis(target_repo)
448
661
 
662
+ # 7. Generate & Launch Interactive Visual Landing Page (Silent by default unless --open)
663
+ welcome_url = None
664
+ try:
665
+ from welcome_page import generate_welcome_page
666
+ should_open = (not no_browser) and open_browser and (not os.environ.get("CI")) and (not os.environ.get("HEADLESS")) and ("unittest" not in sys.modules) and ("pytest" not in sys.modules)
667
+ welcome_file = generate_welcome_page(
668
+ target_repo=target_repo,
669
+ stack_info=stack_info,
670
+ open_browser=should_open
671
+ )
672
+ welcome_url = f"file://{welcome_file}"
673
+ except (ImportError, OSError, ValueError):
674
+ pass
675
+
449
676
  print(f"\n{BOLD}{CYAN}======================================================================{RESET}")
450
677
  print(f"{BOLD}{CYAN} 🎉 PROJECT IS NOW 100% AI-READY (LEVEL 5 SETUP) {RESET}")
451
678
  print(f"{BOLD}{CYAN}======================================================================{RESET}")
452
679
  print(f" Target Framework : {stack_info['framework']}")
680
+ print(f" Active Profile : {profile.upper()}")
453
681
  print(f" AI Project Guide : {os.path.join(target_repo, 'PROJECT_AI_GUIDE.md')}")
454
682
  print(f" Universal Bridges : Cursor (.cursor/rules), Claude Code, Copilot, Windsurf")
455
683
  print(f" Antigravity Plugin : {'ACTIVE (~/.gemini/config/plugins/synapse-hub)' if plugin_injected else 'STANDALONE'}")
456
684
  print(f" AST Method Map : {os.path.join(target_repo, 'repo_map.txt')}")
457
685
  print(f" Health Report : {os.path.join(target_repo, 'PROJECT_HEALTH_REPORT.md')}")
458
686
  print(f" Pre-Push Sentinel : {'ACTIVE (.git/hooks/pre-push)' if hook_installed else 'MANUAL (No .git folder)'}")
687
+ if welcome_url:
688
+ print(f" Visual Landing Page : {welcome_url}")
459
689
  print(f"{BOLD}{CYAN}======================================================================{RESET}\n")
460
690
 
461
691
  return analysis_code
@@ -465,6 +695,24 @@ def main():
465
695
  parser = argparse.ArgumentParser(description="Autonomous Enterprise QA Project Setup")
466
696
  parser.add_argument("target", nargs="?", default=None, help="Target repository path to setup")
467
697
  parser.add_argument("--repo", "--path", dest="repo_path", default=None, help="Target repository path")
698
+ parser.add_argument(
699
+ "--profile",
700
+ default="auto",
701
+ choices=["auto", "core", "web-e2e", "api-perf", "full", "playwright", "pytest", "cypress", "katalon"],
702
+ help="Skills profile to install (auto, core, web-e2e, api-perf, full, playwright, pytest, cypress, katalon)"
703
+ )
704
+ parser.add_argument("--dry-run", action="store_true", help="Simulate setup actions without modifying disk")
705
+ parser.add_argument("--uninstall", action="store_true", help="Revert and remove files installed by setup_project")
706
+ parser.add_argument("--global", action="store_true", dest="enable_global", default=False,
707
+ help="Inject Synapse-Hub into Antigravity global plugins (~/.gemini/config/plugins) and central memory")
708
+ parser.add_argument("--local-only", "--no-global", action="store_true", dest="no_global", default=True,
709
+ help="Only configure project-local assets (PROJECT_AI_GUIDE.md, bridges), do not touch ~/.gemini (default: True)")
710
+ parser.add_argument("--no-git-hook", action="store_true",
711
+ help="Skip installing automated .git/hooks/pre-push")
712
+ parser.add_argument("--open", action="store_true", dest="open_browser",
713
+ help="Launch landing page in web browser")
714
+ parser.add_argument("--no-browser", "--no-open", action="store_true", dest="no_browser", default=True,
715
+ help="Do not automatically launch landing page in web browser (default: True)")
468
716
  args = parser.parse_args()
469
717
 
470
718
  try:
@@ -473,7 +721,23 @@ def main():
473
721
  print(f"❌ Error: {e}")
474
722
  return 1
475
723
 
476
- return run_setup(target_repo)
724
+ if args.uninstall:
725
+ return uninstall_setup(target_repo)
726
+
727
+ # When --open is explicitly requested, honor it
728
+ no_browser = False if getattr(args, "open_browser", False) else True
729
+ open_browser = bool(getattr(args, "open_browser", False))
730
+ use_no_global = False if getattr(args, "enable_global", False) else True
731
+
732
+ return run_setup(
733
+ target_repo,
734
+ dry_run=args.dry_run,
735
+ profile=args.profile,
736
+ no_global=use_no_global,
737
+ no_git_hook=args.no_git_hook,
738
+ no_browser=no_browser,
739
+ open_browser=open_browser
740
+ )
477
741
 
478
742
 
479
743
  if __name__ == "__main__":
@@ -165,7 +165,7 @@ PROHIBITION_PREFIX = re.compile(
165
165
  )
166
166
 
167
167
  ALERT_BLOCK_PREFIX = re.compile(
168
- r"^\s*>\s*\[!(?:WARNING|CAUTION|DANGER|ALERT|IMPORTANT|NOTE|TIP)\]",
168
+ r"^\s*>\s*\[!(?:WARNING|CAUTION|DANGER|ALERT)\]",
169
169
  re.IGNORECASE | re.MULTILINE,
170
170
  )
171
171
 
@@ -189,23 +189,20 @@ def is_in_prohibition_context(content: str, start: int, end: int) -> bool:
189
189
  if PROHIBITION_PREFIX.search(current_line):
190
190
  return True
191
191
 
192
- # 2. Markdown Caution/Warning Callout Block
193
- if any(ALERT_BLOCK_PREFIX.search(line) for line in lines[-5:]):
192
+ # 2. Markdown Caution/Warning Callout Block with explicit negative imperative
193
+ has_alert = any(ALERT_BLOCK_PREFIX.search(line) for line in lines[-5:])
194
+ if has_alert and any(re.search(r'\b(never|do not|don[\'’]t|must not|forbidden|prohibited|avoid)\b', line, re.IGNORECASE) for line in lines[-5:]):
194
195
  return True
195
196
 
196
197
  # 3. Defensive Guideline headings ("Anti-Pattern Blacklist", "Forbidden actions")
197
198
  preceding_lower = preceding_text.lower()
198
199
  defensive_markers = (
199
- "anti-pattern",
200
+ "anti-pattern blacklist",
200
201
  "mistake / anti-pattern",
201
202
  "strictly forbidden",
202
203
  "never use",
203
204
  "mandatory avoidance",
204
205
  "forbidden actions",
205
- "prohibited",
206
- "blacklist",
207
- "threat model",
208
- "vulnerability check",
209
206
  "zero-token error blacklist",
210
207
  )
211
208
  if any(marker in preceding_lower for marker in defensive_markers):
@@ -927,6 +924,9 @@ def scan_target(target_path: str) -> ScanReport:
927
924
  pass
928
925
 
929
926
  path_obj = Path(target_path).resolve()
927
+ if not path_obj.exists():
928
+ raise FileNotFoundError(f"Target path does not exist: {target_path}")
929
+
930
930
  all_findings: List[Finding] = []
931
931
  scanned_count = 0
932
932