synapse-hub 2.5.0 → 2.7.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 (92) hide show
  1. package/.agents/agents/failure-analyst.md +17 -0
  2. package/.agents/agents/orchestrator.md +20 -2
  3. package/.agents/agents/pom-crafter.md +20 -0
  4. package/.agents/agents/quality-gatekeeper.md +20 -2
  5. package/.agents/agents/test-runner.md +16 -0
  6. package/.agents/rules/context-engineering.md +22 -102
  7. package/.agents/rules/git-push-protocol.md +1 -1
  8. package/.agents/rules/graphify.md +2 -0
  9. package/.agents/rules/mandatory-playwright-live.md +9 -9
  10. package/.agents/rules/mobile_appium_rules.md +27 -116
  11. package/.agents/rules/performance_testing_rules.md +18 -62
  12. package/.agents/rules/skill-precedence.md +22 -42
  13. package/.agents/rules/systematic-debugging.md +10 -29
  14. package/.agents/skills/actor-qa-swarm/SKILL.md +77 -0
  15. package/.agents/skills/actor-qa-swarm/examples/broker_sharding_sample.json +12 -0
  16. package/.agents/skills/agentless-qa-repair/SKILL.md +69 -0
  17. package/.agents/skills/agentless-qa-repair/examples/healing_report_sample.json +17 -0
  18. package/.agents/skills/api-spec-to-e2e-matrix/SKILL.md +1 -1
  19. package/.agents/skills/clean-pom-crafter/SKILL.md +2 -2
  20. package/.agents/skills/db-state-verifier-and-seeder/SKILL.md +4 -4
  21. package/.agents/skills/event-stream-qa-orchestrator/SKILL.md +79 -0
  22. package/.agents/skills/event-stream-qa-orchestrator/examples/timeline_sample.jsonl +2 -0
  23. package/.agents/skills/failure-autopsy-and-healing/SKILL.md +2 -2
  24. package/.agents/skills/failure-autopsy-and-healing/scripts/triage_failures.sh +6 -21
  25. package/.agents/skills/katalon-cli-runner/SKILL.md +1 -1
  26. package/.agents/skills/mipro-prompt-compiler/SKILL.md +59 -0
  27. package/.agents/skills/mipro-prompt-compiler/examples/compiled_module_sample.json +22 -0
  28. package/.agents/skills/qa-aci-interface/SKILL.md +67 -0
  29. package/.agents/skills/qa-aci-interface/examples/surgical_edit_sample.json +12 -0
  30. package/.agents/skills/qa-memory-os/SKILL.md +80 -0
  31. package/.agents/skills/qa-memory-os/examples/archival_memory_sample.json +21 -0
  32. package/.agents/skills/review-spec/SKILL.md +60 -0
  33. package/.agents/skills/review-spec/examples/sample_spec_review.md +33 -0
  34. package/.agents/skills/synthetic-test-data-generator/SKILL.md +2 -2
  35. package/.agents/skills/token-and-context-optimizer/references/context_engineering_guide.md +49 -0
  36. package/.agents/skills/tot-exploratory-testing/SKILL.md +59 -0
  37. package/.agents/skills/tot-exploratory-testing/examples/tot_graph_sample.json +35 -0
  38. package/.agents/skills/wcag-audit-patterns/SKILL.md +2 -2
  39. package/.agents/skills/web-agent-gym-benchmarking/SKILL.md +62 -0
  40. package/.agents/skills/web-agent-gym-benchmarking/examples/benchmark_report_sample.json +22 -0
  41. package/AGENTS.md +6 -1
  42. package/CLAUDE.md +1 -1
  43. package/NOTICE +40 -4
  44. package/README.en.md +27 -11
  45. package/README.md +28 -12
  46. package/docs/ARCHITECTURE.md +39 -11
  47. package/docs/adopted-ecosystem-tools.md +9 -0
  48. package/docs/research/EXTERNAL_AGENT_SKILLS_SURVEY.md +1062 -0
  49. package/docs/research/agent_skill_training_analysis.md +1357 -0
  50. package/package.json +1 -1
  51. package/skills_manifest.json +88 -7
  52. package/synapse.config.json +3 -2
  53. package/templates/ai_bridges/CLAUDE.md +1 -1
  54. package/templates/welcome.html.tmpl +34 -25
  55. package/tools/TOOLS_RUNBOOK.md +130 -1
  56. package/tools/__init__.py +1 -1
  57. package/tools/_openapi_parser.py +158 -0
  58. package/tools/agentless_patcher.py +417 -0
  59. package/tools/analyze_project.py +9 -6
  60. package/tools/auto_heal.py +29 -0
  61. package/tools/auto_heal_reflexion.py +172 -0
  62. package/tools/autogen_qa_broker.py +318 -0
  63. package/tools/browser_helpers.js +57 -2
  64. package/tools/browsergym_eval.py +237 -0
  65. package/tools/ci_healing_hook.py +1 -1
  66. package/tools/cli.py +3 -3
  67. package/tools/dashboard_generator.py +29 -13
  68. package/tools/db_sandbox.py +4 -0
  69. package/tools/dspy_qa_signatures.py +357 -0
  70. package/tools/heal_pr_automator.py +25 -0
  71. package/tools/interview_story.py +117 -0
  72. package/tools/lint_ai_docs.py +1 -1
  73. package/tools/mcp_excel_server.py +1 -1
  74. package/tools/mcp_server.py +1 -1
  75. package/tools/mipro_assertion_tuner.py +207 -0
  76. package/tools/pinpoint_failure.py +12 -0
  77. package/tools/project_state.py +4 -0
  78. package/tools/qa_event_stream.py +336 -0
  79. package/tools/reversible_sandbox.py +161 -0
  80. package/tools/safety_firewall.py +28 -0
  81. package/tools/skill_collision_guard.py +231 -0
  82. package/tools/skill_vault.py +343 -0
  83. package/tools/swe_qa_aci.py +369 -0
  84. package/tools/synapse_qa_bench.py +190 -0
  85. package/tools/sync_agent_rules.py +1 -1
  86. package/tools/test_memory_os.py +409 -0
  87. package/tools/textgrad_mutation_optimizer.py +234 -0
  88. package/tools/tot_exploratory_tester.py +240 -0
  89. package/tools/update_sentinel.py +3 -3
  90. package/tools/verify_all.py +35 -4
  91. package/tools/watch_mode.py +1 -1
  92. package/tools/welcome_page.py +2 -2
@@ -0,0 +1,343 @@
1
+ #!/usr/bin/env python3
2
+ # SPDX-FileCopyrightText: Copyright (c) 2026 Thế Vị (@TeeVee998). All rights reserved.
3
+ # SPDX-License-Identifier: MIT
4
+ # Project: Synapse-Hub (https://github.com/TeeVee998/Synapse-Hub)
5
+
6
+ """
7
+ SkillVault Lifelong Page Object Model & Interaction Library (MineDojo / Voyager Pattern)
8
+ ---------------------------------------------------------------------------------------
9
+ Adapts Voyager's self-evolving SkillManager into a persistent SQLite store (.synapse/skill_vault.db).
10
+ When pom-crafter authors new test cases, it queries SkillVault to retrieve existing, verified
11
+ Page Class methods and business interaction primitives, preventing redundant locator generation.
12
+
13
+ Reference:
14
+ - Guanzhi Wang et al. (Voyager: An Open-Ended Embodied Agent with Large Language Models).
15
+ - Synapse-Hub Subsystem 1: Section 6.2 of agent_skill_training_analysis.md.
16
+ """
17
+
18
+ import os
19
+ import sys
20
+ import sqlite3
21
+ import json
22
+ import re
23
+ import difflib
24
+ import argparse
25
+ from dataclasses import dataclass, asdict
26
+ from typing import List, Optional, Dict, Any, Set
27
+
28
+ # Enforce UTF-8 stdout encoding for Windows console compatibility
29
+ if hasattr(sys.stdout, 'reconfigure'):
30
+ try:
31
+ sys.stdout.reconfigure(encoding='utf-8')
32
+ sys.stderr.reconfigure(encoding='utf-8')
33
+ except Exception:
34
+ pass
35
+
36
+
37
+ # Domain synonym ontology for enterprise QA & UI interactions (Offline Fuzzy Semantic Matching)
38
+ QA_SYNONYMS: Dict[str, Set[str]] = {
39
+ "auth": {"login", "signin", "sign-in", "authenticate", "sso", "session", "credential", "token", "password", "user", "oauth"},
40
+ "login": {"auth", "signin", "sign-in", "authenticate", "sso", "session", "credential"},
41
+ "table": {"grid", "datatable", "datagrid", "row", "cell", "column", "pagination", "paging", "list", "tbody"},
42
+ "grid": {"table", "datatable", "datagrid", "row", "cell", "column", "pagination"},
43
+ "pagination": {"paging", "page", "pager", "next-page", "previous", "pagination", "table"},
44
+ "approve": {"accept", "confirm", "reconcile", "verify", "validate", "signoff", "approval", "pass"},
45
+ "modal": {"dialog", "popup", "overlay", "backdrop", "drawer", "alert", "window"},
46
+ "dialog": {"modal", "popup", "overlay", "backdrop", "window"},
47
+ "navigate": {"goto", "route", "url", "visit", "open", "link", "redirect"},
48
+ "button": {"btn", "click", "press", "submit", "action", "trigger"},
49
+ "input": {"textbox", "fill", "type", "enter", "field", "value", "text"},
50
+ "dropdown": {"select", "combobox", "option", "menu", "picker", "choice"},
51
+ "invoice": {"billing", "order", "receipt", "payment", "charge", "reconcile"},
52
+ "cart": {"checkout", "basket", "purchase", "item", "order"},
53
+ "upload": {"attachment", "file", "import", "choose-file", "document"},
54
+ "wait": {"detach", "detached", "sleep", "loading", "spinner", "ready", "networkidle", "smartwait"},
55
+ }
56
+
57
+
58
+ def _expand_tokens_with_synonyms(tokens: List[str]) -> Set[str]:
59
+ """Expands query tokens using the QA domain synonym clusters."""
60
+ expanded = set(tokens)
61
+ for t in tokens:
62
+ if t in QA_SYNONYMS:
63
+ expanded.update(QA_SYNONYMS[t])
64
+ for syn_key, cluster in QA_SYNONYMS.items():
65
+ if t in cluster:
66
+ expanded.add(syn_key)
67
+ expanded.update(cluster)
68
+ return expanded
69
+
70
+
71
+ def _calculate_token_match_score(q_token: str, target_tokens: List[str]) -> float:
72
+ """Computes best match score for a single query token against target corpus tokens."""
73
+ best = 0.0
74
+ for target in target_tokens:
75
+ if q_token == target:
76
+ return 1.0
77
+ if q_token in target or target in q_token:
78
+ best = max(best, 0.8)
79
+ continue
80
+ # Synonym check
81
+ if q_token in QA_SYNONYMS and target in QA_SYNONYMS[q_token]:
82
+ best = max(best, 0.85)
83
+ continue
84
+ # Fuzzy morphological / typo similarity via SequenceMatcher
85
+ ratio = difflib.SequenceMatcher(None, q_token, target).ratio()
86
+ if ratio >= 0.75:
87
+ best = max(best, ratio * 0.8)
88
+ return best
89
+
90
+
91
+ @dataclass
92
+ class PageClassPrimitive:
93
+ skill_id: str # e.g., "SKILL_AUTH_LOGIN_SSO"
94
+ page_class: str # e.g., "LoginPage"
95
+ method_signature: str # e.g., "loginWithSSO(username: str, sso_token: str)"
96
+ method_code: str # Complete executable method body
97
+ locator_tier: int # 1 to 6 (Master Locator Hierarchy)
98
+ semantic_docstring: str # Generated docstring for embedding / retrieval
99
+ verified_on_url: str # Target AUT URL verified against
100
+ mutation_score: float # Verified assertion sensitivity score (>= 80%)
101
+ tags: str = "" # Comma-separated domain tags, e.g. "auth,sso,login"
102
+
103
+
104
+ class SkillVault:
105
+ """Persistent library of verified, self-contained Page Class methods."""
106
+
107
+ def __init__(self, db_path: Optional[str] = None):
108
+ if db_path is None:
109
+ # Anchor to .synapse in workspace or CWD
110
+ base_dir = os.path.join(os.getcwd(), ".synapse")
111
+ os.makedirs(base_dir, exist_ok=True)
112
+ db_path = os.path.join(base_dir, "skill_vault.db")
113
+ self.db_path = db_path
114
+ self._init_schema()
115
+
116
+ def _get_connection(self) -> sqlite3.Connection:
117
+ conn = sqlite3.connect(self.db_path)
118
+ conn.row_factory = sqlite3.Row
119
+ return conn
120
+
121
+ def _init_schema(self):
122
+ with self._get_connection() as conn:
123
+ conn.execute("""
124
+ CREATE TABLE IF NOT EXISTS page_primitives (
125
+ skill_id TEXT PRIMARY KEY,
126
+ page_class TEXT NOT NULL,
127
+ method_signature TEXT NOT NULL,
128
+ method_code TEXT NOT NULL,
129
+ locator_tier INTEGER DEFAULT 1,
130
+ semantic_docstring TEXT,
131
+ verified_on_url TEXT,
132
+ mutation_score REAL DEFAULT 0.0,
133
+ tags TEXT DEFAULT '',
134
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
135
+ );
136
+ """)
137
+ conn.execute("CREATE INDEX IF NOT EXISTS idx_page_class ON page_primitives(page_class);")
138
+ conn.execute("CREATE INDEX IF NOT EXISTS idx_method_sig ON page_primitives(method_signature);")
139
+ # Auto-migrate: check if tags column exists
140
+ try:
141
+ cursor = conn.execute("PRAGMA table_info(page_primitives)")
142
+ cols = [row["name"] for row in cursor.fetchall()]
143
+ if "tags" not in cols:
144
+ conn.execute("ALTER TABLE page_primitives ADD COLUMN tags TEXT DEFAULT '';")
145
+ except Exception as e:
146
+ # Column check non-fatal during migration
147
+ sys.stderr.write(f"Notice: table migration skipped: {e}\n")
148
+
149
+ def register_primitive(self, primitive: PageClassPrimitive) -> bool:
150
+ """Persists a verified Page Class primitive."""
151
+ try:
152
+ with self._get_connection() as conn:
153
+ conn.execute("""
154
+ INSERT OR REPLACE INTO page_primitives (
155
+ skill_id, page_class, method_signature, method_code,
156
+ locator_tier, semantic_docstring, verified_on_url, mutation_score, tags
157
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?);
158
+ """, (
159
+ primitive.skill_id,
160
+ primitive.page_class,
161
+ primitive.method_signature,
162
+ primitive.method_code,
163
+ primitive.locator_tier,
164
+ primitive.semantic_docstring,
165
+ primitive.verified_on_url,
166
+ primitive.mutation_score,
167
+ primitive.tags
168
+ ))
169
+ return True
170
+ except sqlite3.Error as e:
171
+ sys.stderr.write(f"SkillVault Error: {e}\n")
172
+ return False
173
+
174
+ def query_primitives(self, query: str, top_k: int = 5, tag: Optional[str] = None, min_score: float = 0.15) -> List[Dict[str, Any]]:
175
+ """
176
+ Queries verified primitives using intelligent fuzzy semantic matching:
177
+ combines exact tokens, synonym expansion, n-gram substring match, and SequenceMatcher similarity.
178
+ """
179
+ raw_tokens = [t.lower() for t in re.findall(r'[a-zA-Z0-9_-]+', query) if len(t) >= 2]
180
+ if not raw_tokens and not tag:
181
+ return self.list_primitives(limit=top_k)
182
+
183
+ expanded_tokens = _expand_tokens_with_synonyms(raw_tokens) if raw_tokens else set()
184
+
185
+ with self._get_connection() as conn:
186
+ if tag:
187
+ rows = conn.execute("SELECT * FROM page_primitives WHERE tags LIKE ?", (f"%{tag}%",)).fetchall()
188
+ else:
189
+ rows = conn.execute("SELECT * FROM page_primitives").fetchall()
190
+
191
+ if not raw_tokens:
192
+ return [dict(r) for r in rows[:top_k]]
193
+
194
+ scored = []
195
+ for r in rows:
196
+ corpus_text = f"{r['page_class']} {r['method_signature']} {r['semantic_docstring'] or ''} {r['tags'] or ''}".lower()
197
+ corpus_tokens = [t.lower() for t in re.findall(r'[a-zA-Z0-9_-]+', corpus_text) if len(t) >= 2]
198
+
199
+ # Calculate individual query token matches
200
+ token_scores = [_calculate_token_match_score(qt, corpus_tokens) for qt in raw_tokens]
201
+ avg_token_score = sum(token_scores) / len(token_scores) if token_scores else 0.0
202
+
203
+ # Synonym boost
204
+ synonym_hits = sum(1 for st in expanded_tokens if st in corpus_text)
205
+ synonym_factor = min(0.3, (synonym_hits / max(1, len(expanded_tokens))) * 0.3)
206
+
207
+ # Mutation score quality boost (up to +0.1 for high mutation score)
208
+ mut_score = r["mutation_score"] or 0.0
209
+ mutation_boost = (mut_score / 100.0) * 0.1
210
+
211
+ total_relevance = round(min(1.0, (avg_token_score * 0.7) + synonym_factor + mutation_boost), 4)
212
+
213
+ # Pass if relevance reaches threshold OR direct substring match exists
214
+ if total_relevance >= min_score or any(qt in corpus_text for qt in raw_tokens):
215
+ item = dict(r)
216
+ item["relevance_score"] = total_relevance
217
+ item["relevance_percentage"] = f"{round(total_relevance * 100, 1)}%"
218
+ scored.append(item)
219
+
220
+ scored.sort(key=lambda x: (x["relevance_score"], x["mutation_score"]), reverse=True)
221
+ return scored[:top_k]
222
+
223
+ def list_primitives(self, limit: int = 50) -> List[Dict[str, Any]]:
224
+ with self._get_connection() as conn:
225
+ rows = conn.execute("SELECT * FROM page_primitives ORDER BY created_at DESC LIMIT ?", (limit,)).fetchall()
226
+ return [dict(r) for r in rows]
227
+
228
+
229
+ def main():
230
+ parser = argparse.ArgumentParser(description="SkillVault Lifelong POM Library")
231
+ parser.add_argument("--query", default=None, help="Query verified primitives by keyword (fuzzy semantic search)")
232
+ parser.add_argument("--tag", default=None, help="Filter primitives by domain tag (e.g. auth, table, invoice)")
233
+ parser.add_argument("--list", action="store_true", help="List all stored primitives")
234
+ parser.add_argument("--seed-samples", action="store_true", help="Seed initial verified POM primitives")
235
+ args = parser.parse_args()
236
+
237
+ vault = SkillVault()
238
+
239
+ if args.seed_samples:
240
+ samples = [
241
+ PageClassPrimitive(
242
+ skill_id="SKILL_AUTH_LOGIN_SSO",
243
+ page_class="LoginPage",
244
+ method_signature="loginWithSSO(username: str, sso_token: str)",
245
+ method_code="""def loginWithSSO(self, username: str, sso_token: str):
246
+ self.page.goto("/auth/sso")
247
+ self.page.getByRole("textbox", name="SSO User").fill(username)
248
+ self.page.getByRole("textbox", name="Token").fill(sso_token)
249
+ self.page.getByRole("button", name="Authenticate").click()
250
+ self.page.waitForLoadState("networkidle")""",
251
+ locator_tier=1,
252
+ semantic_docstring="Authenticates user through enterprise SSO portal with token and networkidle smart wait.",
253
+ verified_on_url="https://app.enterprise.com/auth/sso",
254
+ mutation_score=92.5,
255
+ tags="auth,login,signin,sso,security"
256
+ ),
257
+ PageClassPrimitive(
258
+ skill_id="SKILL_INVOICE_APPROVE_RECONCILE",
259
+ page_class="InvoicePage",
260
+ method_signature="approveAndReconcileInvoice(invoice_code: str)",
261
+ method_code="""def approveAndReconcileInvoice(self, invoice_code: str):
262
+ self.page.getByRole("row", name=invoice_code).getByRole("button", name="Approve").click()
263
+ self.page.getByRole("button", name="Confirm Approval").click()
264
+ self.page.waitForSelector(".p-component-overlay", state="detached")""",
265
+ locator_tier=1,
266
+ semantic_docstring="Approves and reconciles invoice row item with modal overlay detachment verification.",
267
+ verified_on_url="https://app.enterprise.com/invoices",
268
+ mutation_score=88.0,
269
+ tags="invoice,billing,approve,reconcile,modal"
270
+ ),
271
+ PageClassPrimitive(
272
+ skill_id="SKILL_TABLE_PAGINATION_NAV",
273
+ page_class="DataTableComponent",
274
+ method_signature="navigateToNextPage(expected_min_rows: int = 1)",
275
+ method_code="""def navigateToNextPage(self, expected_min_rows: int = 1):
276
+ next_btn = self.page.getByRole("button", name="Next Page")
277
+ if next_btn.is_enabled():
278
+ next_btn.click()
279
+ self.page.waitForSelector(".loading-shimmer", state="detached")
280
+ rows = self.page.getByRole("row").all()
281
+ assert len(rows) >= expected_min_rows, f"Expected at least {expected_min_rows} rows" """,
282
+ locator_tier=1,
283
+ semantic_docstring="Navigates through paginated grid/table with dynamic shimmer detachment and row count assertion.",
284
+ verified_on_url="https://app.enterprise.com/data-grid",
285
+ mutation_score=90.0,
286
+ tags="table,grid,pagination,paging,navigation"
287
+ ),
288
+ PageClassPrimitive(
289
+ skill_id="SKILL_FORM_MODAL_SUBMIT",
290
+ page_class="UserManagementPage",
291
+ method_signature="fillAndSubmitModalForm(user_data: dict)",
292
+ method_code="""def fillAndSubmitModalForm(self, user_data: dict):
293
+ dialog = self.page.getByRole("dialog")
294
+ dialog.getByRole("textbox", name="Full Name").fill(user_data.get("name", ""))
295
+ dialog.getByRole("textbox", name="Email").fill(user_data.get("email", ""))
296
+ dialog.getByRole("combobox", name="Role").selectOption(user_data.get("role", "Viewer"))
297
+ dialog.getByRole("button", name="Save").click()
298
+ self.page.waitForSelector(".toast-success", state="visible")""",
299
+ locator_tier=1,
300
+ semantic_docstring="Fills interactive modal dialog form and validates submission toast notification.",
301
+ verified_on_url="https://app.enterprise.com/users",
302
+ mutation_score=87.5,
303
+ tags="modal,dialog,form,input,submit"
304
+ ),
305
+ PageClassPrimitive(
306
+ skill_id="SKILL_ATTACHMENT_UPLOAD_VERIFY",
307
+ page_class="DocumentManagementPage",
308
+ method_signature="uploadAttachmentAndVerify(file_path: str, expected_filename: str)",
309
+ method_code="""def uploadAttachmentAndVerify(self, file_path: str, expected_filename: str):
310
+ file_input = self.page.locator("input[type='file']")
311
+ file_input.setInputFiles(file_path)
312
+ self.page.waitForSelector(".upload-progress", state="detached")
313
+ badge = self.page.getByText(expected_filename)
314
+ assert badge.is_visible(), f"Expected uploaded file badge '{expected_filename}' to be visible" """,
315
+ locator_tier=1,
316
+ semantic_docstring="Uploads file attachment, waits for progress bar detachment and asserts filename badge.",
317
+ verified_on_url="https://app.enterprise.com/documents",
318
+ mutation_score=94.0,
319
+ tags="upload,attachment,file,document,verify"
320
+ )
321
+ ]
322
+ for s in samples:
323
+ vault.register_primitive(s)
324
+ print(f"✅ Seeded {len(samples)} verified PageClass primitives into SkillVault.")
325
+ return 0
326
+
327
+ if args.list:
328
+ items = vault.list_primitives()
329
+ print(json.dumps(items, indent=2))
330
+ return 0
331
+
332
+ if args.query or args.tag:
333
+ matches = vault.query_primitives(args.query or "", tag=args.tag)
334
+ print(f"🔍 Found {len(matches)} matching primitives in SkillVault (Fuzzy Semantic Search):")
335
+ print(json.dumps(matches, indent=2))
336
+ return 0
337
+
338
+ print("SkillVault active. Use --query, --tag, --list, or --seed-samples.")
339
+ return 0
340
+
341
+
342
+ if __name__ == "__main__":
343
+ sys.exit(main())