synapse-hub 2.4.3 → 2.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agents/agents/failure-analyst.md +13 -0
- package/.agents/agents/orchestrator.md +5 -2
- package/.agents/agents/pom-crafter.md +13 -0
- package/.agents/agents/quality-gatekeeper.md +21 -2
- package/.agents/agents/test-runner.md +11 -0
- package/.agents/rules/context-engineering.md +22 -102
- package/.agents/rules/mobile_appium_rules.md +19 -115
- package/.agents/rules/performance_testing_rules.md +18 -62
- package/.agents/rules/skill-precedence.md +24 -24
- package/.agents/rules/systematic-debugging.md +10 -27
- package/.agents/skills/lean-code-ladder/SKILL.md +12 -1
- package/.agents/skills/lean-impact-scoreboard/SKILL.md +48 -0
- package/.agents/skills/lean-impact-scoreboard/examples/sample_benchmark_gain.md +20 -0
- package/.agents/skills/lean-impact-scoreboard/examples/sample_scoreboard.md +15 -0
- package/.agents/skills/repo-quality-audit/SKILL.md +68 -0
- package/.agents/skills/repo-quality-audit/examples/sample_audit_walkthrough.md +15 -0
- package/.agents/skills/repo-quality-audit/examples/sample_repo_audit.md +33 -0
- package/.agents/skills/senior-code-review/SKILL.md +90 -0
- package/.agents/skills/senior-code-review/examples/sample_review_walkthrough.md +29 -0
- package/.agents/skills/technical-debt-harvester/SKILL.md +70 -0
- package/.agents/skills/technical-debt-harvester/examples/sample_debt_ledger.md +25 -0
- package/.agents/skills/technical-debt-harvester/examples/sample_ledger_output.md +20 -0
- package/.agents/skills/token-and-context-optimizer/references/context_engineering_guide.md +49 -0
- package/.cursor/rules/synapse-qa.mdc +4 -3
- package/.cursorrules +1 -0
- package/.windsurfrules +1 -0
- package/AGENTS.md +57 -180
- package/CLAUDE.md +5 -0
- package/NOTICE +40 -4
- package/README.en.md +33 -13
- package/README.md +36 -16
- package/bin/agent-qa.js +3 -2
- package/docs/ARCHITECTURE.md +39 -11
- package/docs/CLI_REFERENCE.md +15 -1
- package/docs/adopted-ecosystem-tools.md +9 -0
- package/docs/research/agent_skill_training_analysis.md +1357 -0
- package/package.json +1 -3
- package/skills_manifest.json +39 -3
- package/synapse.config.json +3 -2
- package/templates/ai_bridges/CLAUDE.md +5 -0
- package/templates/ai_bridges/copilot-instructions.md +2 -0
- package/templates/ai_bridges/cursor_synapse_qa.mdc +4 -3
- package/templates/ai_bridges/windsurfrules +1 -0
- package/templates/welcome.html.tmpl +34 -25
- package/tools/.infer_baseline.json +7 -1079
- package/tools/TOOLS_RUNBOOK.md +182 -13
- package/tools/__init__.py +1 -1
- package/tools/agent_canary.py +4 -4
- package/tools/analyze_project.py +2 -2
- package/tools/api_fuzzer.py +4 -4
- package/tools/auto_heal.py +14 -2
- package/tools/auto_heal_reflexion.py +172 -0
- package/tools/browser_helpers.js +57 -2
- package/tools/bump_version.py +30 -2
- package/tools/cache_resolver.py +6 -6
- package/tools/check_env.py +13 -7
- package/tools/cli.py +265 -197
- package/tools/count_tokens.py +7 -7
- package/tools/dashboard_generator.py +39 -23
- package/tools/db_sandbox.py +5 -5
- package/tools/debt_harvester.py +236 -0
- package/tools/distill_log.py +2 -2
- package/tools/dspy_qa_signatures.py +357 -0
- package/tools/flaky_detector.py +5 -5
- package/tools/generate_tc_from_story.py +2 -2
- package/tools/generate_test_reports.py +4 -4
- package/tools/git_pre_commit_guard.py +6 -6
- package/tools/infer_linter.py +12 -7
- package/tools/interview_story.py +117 -0
- package/tools/lint_ai_docs.py +3 -3
- package/tools/matrix_sharder.py +4 -4
- package/tools/mcp_excel_server.py +1 -1
- package/tools/mcp_server.py +3 -3
- package/tools/micro_mutator.py +6 -6
- package/tools/omni_transpiler.py +2 -2
- package/tools/output_formatter.py +37 -2
- package/tools/pinpoint_failure.py +4 -1
- package/tools/repo_map.py +2 -2
- package/tools/reversible_sandbox.py +157 -0
- package/tools/safety_firewall.py +30 -2
- package/tools/senior_code_review.py +341 -0
- package/tools/setup_project.py +9 -9
- package/tools/skill_collision_guard.py +231 -0
- package/tools/skill_vault.py +343 -0
- package/tools/skillspector.py +2 -2
- package/tools/synapse_qa_bench.py +190 -0
- package/tools/sync_agent_rules.py +14 -3
- package/tools/test_impact.py +4 -4
- package/tools/textgrad_mutation_optimizer.py +234 -0
- package/tools/tms_sync_bridge.py +2 -2
- package/tools/update_sentinel.py +17 -17
- package/tools/verify_all.py +47 -16
- package/tools/visual_som_helper.py +8 -8
- package/tools/watch_mode.py +7 -8
- package/tools/wcag_audit.py +5 -1
- package/tools/welcome_page.py +12 -12
- package/benchmarks/qa_eval/README.md +0 -71
- package/benchmarks/qa_eval/build_dataset.py +0 -677
- package/benchmarks/qa_eval/dataset/api_contract_drift/qa-challenge-06_api_contract_drift.json +0 -22
- package/benchmarks/qa_eval/dataset/api_contract_drift/qa-challenge-07_api_contract_drift.json +0 -22
- package/benchmarks/qa_eval/dataset/api_contract_drift/qa-challenge-08_api_contract_drift.json +0 -22
- package/benchmarks/qa_eval/dataset/api_contract_drift/qa-challenge-09_api_contract_drift.json +0 -22
- package/benchmarks/qa_eval/dataset/api_contract_drift/qa-challenge-10_api_contract_drift.json +0 -22
- package/benchmarks/qa_eval/dataset/fake_pass_tautology/qa-challenge-21_fake_pass_tautology.json +0 -21
- package/benchmarks/qa_eval/dataset/fake_pass_tautology/qa-challenge-22_fake_pass_tautology.json +0 -21
- package/benchmarks/qa_eval/dataset/fake_pass_tautology/qa-challenge-23_fake_pass_tautology.json +0 -21
- package/benchmarks/qa_eval/dataset/fake_pass_tautology/qa-challenge-24_fake_pass_tautology.json +0 -21
- package/benchmarks/qa_eval/dataset/fake_pass_tautology/qa-challenge-25_fake_pass_tautology.json +0 -21
- package/benchmarks/qa_eval/dataset/locator_drift/qa-challenge-01_locator_drift.json +0 -23
- package/benchmarks/qa_eval/dataset/locator_drift/qa-challenge-02_locator_drift.json +0 -23
- package/benchmarks/qa_eval/dataset/locator_drift/qa-challenge-03_locator_drift.json +0 -23
- package/benchmarks/qa_eval/dataset/locator_drift/qa-challenge-04_locator_drift.json +0 -23
- package/benchmarks/qa_eval/dataset/locator_drift/qa-challenge-05_locator_drift.json +0 -23
- package/benchmarks/qa_eval/dataset/stale_and_mutation/qa-challenge-16_stale_and_mutation.json +0 -22
- package/benchmarks/qa_eval/dataset/stale_and_mutation/qa-challenge-17_stale_and_mutation.json +0 -22
- package/benchmarks/qa_eval/dataset/stale_and_mutation/qa-challenge-18_stale_and_mutation.json +0 -22
- package/benchmarks/qa_eval/dataset/stale_and_mutation/qa-challenge-19_stale_and_mutation.json +0 -22
- package/benchmarks/qa_eval/dataset/stale_and_mutation/qa-challenge-20_stale_and_mutation.json +0 -23
- package/benchmarks/qa_eval/dataset/timing_and_race/qa-challenge-11_timing_and_race.json +0 -22
- package/benchmarks/qa_eval/dataset/timing_and_race/qa-challenge-12_timing_and_race.json +0 -22
- package/benchmarks/qa_eval/dataset/timing_and_race/qa-challenge-13_timing_and_race.json +0 -22
- package/benchmarks/qa_eval/dataset/timing_and_race/qa-challenge-14_timing_and_race.json +0 -22
- package/benchmarks/qa_eval/dataset/timing_and_race/qa-challenge-15_timing_and_race.json +0 -22
- package/benchmarks/qa_eval/eval_runner.py +0 -418
- package/examples/cypress-ecommerce-suite/README.md +0 -45
- package/examples/cypress-ecommerce-suite/cypress/e2e/checkout.cy.js +0 -17
- package/examples/cypress-ecommerce-suite/cypress/pages/BasePage.js +0 -29
- package/examples/cypress-ecommerce-suite/cypress/pages/CartPage.js +0 -51
- package/examples/cypress-ecommerce-suite/cypress.config.js +0 -13
- package/examples/cypress-ecommerce-suite/package.json +0 -13
- package/examples/katalon-suite/Keywords/pages/BasePage.groovy +0 -19
- package/examples/katalon-suite/Keywords/pages/DashboardPage.groovy +0 -29
- package/examples/katalon-suite/Keywords/pages/LoginPage.groovy +0 -45
- package/examples/katalon-suite/Profiles/default.glbl +0 -12
- package/examples/katalon-suite/README.md +0 -18
- package/examples/katalon-suite/Scripts/Auth/TC_LoginSuccess/Script1234567890.groovy +0 -12
- package/examples/katalon-suite/Scripts/Dashboard/TC_ViewSummary/Script1234567891.groovy +0 -15
- package/examples/katalon-suite/katalon_suite.prj +0 -21
- package/examples/playwright-crm-suite/README.md +0 -40
- package/examples/playwright-crm-suite/package.json +0 -14
- package/examples/playwright-crm-suite/pages/BasePage.ts +0 -37
- package/examples/playwright-crm-suite/pages/CustomerPage.ts +0 -57
- package/examples/playwright-crm-suite/pages/LoginPage.ts +0 -32
- package/examples/playwright-crm-suite/playwright.config.ts +0 -27
- package/examples/playwright-crm-suite/tests/auth.spec.ts +0 -22
- package/examples/playwright-crm-suite/tests/customers.spec.ts +0 -33
- package/examples/plugins/sample-custom-plugin/README.md +0 -14
- package/examples/plugins/sample-custom-plugin/plugin.json +0 -16
- package/examples/plugins/sample-custom-plugin/skills/custom-security-headers-audit/SKILL.md +0 -29
- package/examples/plugins/sample-custom-plugin/skills/custom-security-headers-audit/examples/audit_fixture.json +0 -8
- package/examples/plugins/sample-custom-plugin/tools/custom_security_headers.py +0 -125
- package/examples/practices/README.md +0 -22
- package/examples/practices/requirements/crm/requirements_contracts.md +0 -292
- package/examples/practices/requirements/crm/requirements_customers.md +0 -462
- package/examples/practices/requirements/crm/requirements_login.md +0 -202
- package/examples/practices/requirements/crm/requirements_projects.md +0 -396
- package/examples/practices/requirements/crm/requirements_tasks.md +0 -343
- package/examples/practices/requirements/ecommerce/requirements_category_brand.txt +0 -402
- 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 +0 -52
- 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 +0 -119
- package/examples/practices/requirements/jira/KAN-5/KAN-5_overview.md +0 -9
- 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 +0 -32
- package/examples/practices/testcases/api/book_management_api_test_cases.md +0 -144
- package/examples/practices/testcases/api/user_management_api_test_cases.md +0 -139
- package/examples/practices/testcases/crm/test_cases_crm_login.md +0 -148
- package/examples/practices/testcases/crm/test_cases_customers.md +0 -156
- package/examples/pytest-api-suite/README.md +0 -45
- package/examples/pytest-api-suite/conftest.py +0 -31
- package/examples/pytest-api-suite/pages/user_api_client.py +0 -36
- package/examples/pytest-api-suite/requirements.txt +0 -2
- package/examples/pytest-api-suite/tests/test_user_api.py +0 -44
- package/examples/selenium-suite/README.md +0 -18
- package/examples/selenium-suite/pages/base_page.py +0 -27
- package/examples/selenium-suite/pages/login_page.py +0 -29
- package/examples/selenium-suite/pages/order_page.py +0 -25
- package/examples/selenium-suite/pytest.ini +0 -6
- package/examples/selenium-suite/requirements.txt +0 -2
- package/examples/selenium-suite/tests/test_login.py +0 -10
- package/examples/selenium-suite/tests/test_order.py +0 -10
package/tools/browser_helpers.js
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
(function () {
|
|
14
14
|
'use strict';
|
|
15
15
|
|
|
16
|
-
if (window.__qa && window.__qa.__version === '2.
|
|
16
|
+
if (window.__qa && window.__qa.__version === '2.5.0') {
|
|
17
17
|
return window.__qa;
|
|
18
18
|
}
|
|
19
19
|
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
const qa = {
|
|
50
|
-
__version: '2.
|
|
50
|
+
__version: '2.5.0',
|
|
51
51
|
|
|
52
52
|
/**
|
|
53
53
|
* 1. Smart Action Batching
|
|
@@ -682,6 +682,61 @@
|
|
|
682
682
|
|
|
683
683
|
check();
|
|
684
684
|
});
|
|
685
|
+
},
|
|
686
|
+
|
|
687
|
+
/**
|
|
688
|
+
* 9. DFSDT Backtracking Locator Resolver (ToolBench / Master Locator Hierarchy Pattern)
|
|
689
|
+
* Executes Depth-First Search across 6 architectural locator tiers when a selector fails or goes stale.
|
|
690
|
+
* Evaluates DOM presence, visibility, and clickability before returning the resilient candidate.
|
|
691
|
+
* @param {Object|string} spec { testId, role, text, formControl, id, css } or broken selector string
|
|
692
|
+
* @returns {Object} { resolved: boolean, tier: number, selector: string, element: HTMLElement|null }
|
|
693
|
+
*/
|
|
694
|
+
dfsdtResolve: function (spec) {
|
|
695
|
+
if (typeof document === 'undefined') {
|
|
696
|
+
return { resolved: false, tier: 0, selector: null, element: null };
|
|
697
|
+
}
|
|
698
|
+
const candidates = [];
|
|
699
|
+
if (typeof spec === 'string') {
|
|
700
|
+
const clean = spec.replace(/['"\\\[\]]/g, '').trim();
|
|
701
|
+
candidates.push({ tier: 1, sel: `[data-testid="${clean}"]` });
|
|
702
|
+
candidates.push({ tier: 2, sel: `[role="button"][name="${clean}"], [role="textbox"][name="${clean}"]` });
|
|
703
|
+
candidates.push({ tier: 2, sel: `button:has-text("${clean}"), a:has-text("${clean}")` });
|
|
704
|
+
candidates.push({ tier: 3, sel: `[formcontrolname="${clean}"]` });
|
|
705
|
+
candidates.push({ tier: 3, sel: `[name="${clean}"]` });
|
|
706
|
+
candidates.push({ tier: 4, sel: `#${clean}` });
|
|
707
|
+
} else if (spec && typeof spec === 'object') {
|
|
708
|
+
if (spec.testId) candidates.push({ tier: 1, sel: `[data-testid="${spec.testId}"]` });
|
|
709
|
+
if (spec.role && spec.name) candidates.push({ tier: 1, sel: `[role="${spec.role}"][name="${spec.name}"]` });
|
|
710
|
+
if (spec.text) candidates.push({ tier: 2, sel: `button:has-text("${spec.text}"), a:has-text("${spec.text}"), span:has-text("${spec.text}")` });
|
|
711
|
+
if (spec.formControl) candidates.push({ tier: 3, sel: `[formcontrolname="${spec.formControl}"]` });
|
|
712
|
+
if (spec.name) candidates.push({ tier: 3, sel: `[name="${spec.name}"]` });
|
|
713
|
+
if (spec.id) candidates.push({ tier: 4, sel: `#${spec.id}` });
|
|
714
|
+
if (spec.css) candidates.push({ tier: 5, sel: spec.css });
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
// DFSDT Backtracking evaluation
|
|
718
|
+
for (const cand of candidates) {
|
|
719
|
+
try {
|
|
720
|
+
const els = Array.from(document.querySelectorAll(cand.sel));
|
|
721
|
+
for (const el of els) {
|
|
722
|
+
const rect = el.getBoundingClientRect();
|
|
723
|
+
const isVisible = !!(rect.width > 0 && rect.height > 0 && window.getComputedStyle(el).display !== 'none' && window.getComputedStyle(el).visibility !== 'hidden');
|
|
724
|
+
if (isVisible) {
|
|
725
|
+
return {
|
|
726
|
+
resolved: true,
|
|
727
|
+
tier: cand.tier,
|
|
728
|
+
selector: cand.sel,
|
|
729
|
+
element: el
|
|
730
|
+
};
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
} catch (e) {
|
|
734
|
+
// Backtrack to next candidate tier
|
|
735
|
+
continue;
|
|
736
|
+
}
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
return { resolved: false, tier: 0, selector: null, element: null };
|
|
685
740
|
}
|
|
686
741
|
};
|
|
687
742
|
|
package/tools/bump_version.py
CHANGED
|
@@ -142,7 +142,18 @@ def git_commit_and_tag(version: str, push: bool = False):
|
|
|
142
142
|
|
|
143
143
|
if push:
|
|
144
144
|
print(f"🚀 Pushing commit and tags to remote origin...")
|
|
145
|
-
subprocess.run(["git", "
|
|
145
|
+
res = subprocess.run(["git", "branch", "--show-current"], cwd=REPO_ROOT, stdout=subprocess.PIPE, text=True)
|
|
146
|
+
cur_branch = res.stdout.strip()
|
|
147
|
+
if cur_branch == "develop":
|
|
148
|
+
try:
|
|
149
|
+
subprocess.run(["git", "checkout", "main"], cwd=REPO_ROOT, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
|
150
|
+
subprocess.run(["git", "merge", "develop", "--ff-only"], cwd=REPO_ROOT, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
|
151
|
+
subprocess.run(["git", "checkout", "develop"], cwd=REPO_ROOT, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
|
152
|
+
subprocess.run(["git", "push", "origin", "develop", "main", "--tags"], cwd=REPO_ROOT, check=True)
|
|
153
|
+
except Exception:
|
|
154
|
+
subprocess.run(["git", "push", "origin", "HEAD", "--tags"], cwd=REPO_ROOT, check=True)
|
|
155
|
+
else:
|
|
156
|
+
subprocess.run(["git", "push", "origin", "HEAD", "--tags"], cwd=REPO_ROOT, check=True)
|
|
146
157
|
print(f"✅ Remote origin synchronized.")
|
|
147
158
|
|
|
148
159
|
def main():
|
|
@@ -174,7 +185,7 @@ def main():
|
|
|
174
185
|
update_json_root_version("plugin.json", new_ver, args.dry_run)
|
|
175
186
|
|
|
176
187
|
# 2. pyproject.toml
|
|
177
|
-
update_file("pyproject.toml", r'(version\s*=\s*")[^"]+(")', rf"\g<1>{new_ver}\g<2>", args.dry_run)
|
|
188
|
+
update_file("pyproject.toml", r'(?m)^(\s*version\s*=\s*")[^"]+(")', rf"\g<1>{new_ver}\g<2>", args.dry_run)
|
|
178
189
|
|
|
179
190
|
# 3. skills_manifest.json
|
|
180
191
|
update_json_root_version("skills_manifest.json", new_ver, args.dry_run)
|
|
@@ -222,6 +233,23 @@ def main():
|
|
|
222
233
|
update_file("tools/update_sentinel.py", r'(\.get\("version",\s*")[^"]+(")', rf"\g<1>{new_ver}\g<2>", args.dry_run)
|
|
223
234
|
update_file("tools/update_sentinel.py", r'(return\s*")[0-9]+\.[0-9]+\.[0-9]+(")', rf"\g<1>{new_ver}\g<2>", args.dry_run)
|
|
224
235
|
|
|
236
|
+
# 14. CHANGELOG.md
|
|
237
|
+
cl_path = os.path.join(REPO_ROOT, "CHANGELOG.md")
|
|
238
|
+
if os.path.exists(cl_path) and not args.dry_run:
|
|
239
|
+
try:
|
|
240
|
+
with open(cl_path, "r", encoding="utf-8") as f:
|
|
241
|
+
cl_text = f.read()
|
|
242
|
+
if f"## [{new_ver}]" not in cl_text:
|
|
243
|
+
from datetime import date
|
|
244
|
+
today_str = date.today().isoformat()
|
|
245
|
+
new_block = f"---\n\n## [{new_ver}] - {today_str}\n\n### Changed\n- Maintenance & version release v{new_ver}.\n\n"
|
|
246
|
+
cl_text = re.sub(r'(?m)^---\s*\n\s*##\s*\[', new_block + "## [", cl_text, count=1)
|
|
247
|
+
with open(cl_path, "w", encoding="utf-8") as f:
|
|
248
|
+
f.write(cl_text)
|
|
249
|
+
print(f" [UPDATED] CHANGELOG.md (v{new_ver} entry added)")
|
|
250
|
+
except Exception as e:
|
|
251
|
+
print(f" [WARN] CHANGELOG.md update notice: {e}")
|
|
252
|
+
|
|
225
253
|
if args.dry_run:
|
|
226
254
|
print("\n[INFO] Dry-run completed. No files modified on disk.")
|
|
227
255
|
return
|
package/tools/cache_resolver.py
CHANGED
|
@@ -285,8 +285,8 @@ def get_db(db_path=None, timeout=30.0):
|
|
|
285
285
|
conn.execute("PRAGMA journal_mode=WAL;")
|
|
286
286
|
conn.execute("PRAGMA synchronous=NORMAL;")
|
|
287
287
|
conn.execute("PRAGMA busy_timeout=30000;")
|
|
288
|
-
except
|
|
289
|
-
|
|
288
|
+
except sqlite3.Error as e:
|
|
289
|
+
sys.stderr.write(f"Notice: SQLite PRAGMA configuration skipped: {e}\n")
|
|
290
290
|
return conn
|
|
291
291
|
|
|
292
292
|
|
|
@@ -312,8 +312,8 @@ def init_db(seed=True, target_db=None):
|
|
|
312
312
|
""")
|
|
313
313
|
try:
|
|
314
314
|
cursor.execute("ALTER TABLE healing_cache ADD COLUMN code_patch TEXT DEFAULT ''")
|
|
315
|
-
except
|
|
316
|
-
|
|
315
|
+
except sqlite3.OperationalError:
|
|
316
|
+
column_exists = True
|
|
317
317
|
|
|
318
318
|
# 2. Negative Memory Table (Blacklist of Failed Fix Attempts)
|
|
319
319
|
cursor.execute("""
|
|
@@ -372,8 +372,8 @@ def init_db(seed=True, target_db=None):
|
|
|
372
372
|
""", (r["error_signature"], r["module_name"], r["symptom"], r["root_cause"], r["groovy_patch"], r["hit_count"]))
|
|
373
373
|
conn.commit()
|
|
374
374
|
local_conn.close()
|
|
375
|
-
except
|
|
376
|
-
|
|
375
|
+
except (sqlite3.Error, OSError) as e:
|
|
376
|
+
sys.stderr.write(f"Notice: Local cache migration skipped: {e}\n")
|
|
377
377
|
|
|
378
378
|
if seed:
|
|
379
379
|
for s in SEED_SOLUTIONS:
|
package/tools/check_env.py
CHANGED
|
@@ -13,6 +13,7 @@ Autonomously detects Target Project or QA Hub (CLI, CWD, ENV).
|
|
|
13
13
|
import os
|
|
14
14
|
import sys
|
|
15
15
|
import shutil
|
|
16
|
+
import shlex
|
|
16
17
|
import platform
|
|
17
18
|
import subprocess
|
|
18
19
|
import argparse
|
|
@@ -89,8 +90,13 @@ class DiagnosticRunner:
|
|
|
89
90
|
|
|
90
91
|
def run_command(self, cmd, timeout: float = 15.0):
|
|
91
92
|
try:
|
|
92
|
-
|
|
93
|
-
|
|
93
|
+
if isinstance(cmd, str):
|
|
94
|
+
cmd_args = shlex.split(cmd, posix=(platform.system() != "Windows"))
|
|
95
|
+
else:
|
|
96
|
+
cmd_args = list(cmd)
|
|
97
|
+
res = subprocess.run(cmd_args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, shell=False, timeout=timeout)
|
|
98
|
+
out = res.stdout.strip() if res.stdout.strip() else res.stderr.strip()
|
|
99
|
+
return res.returncode == 0, out
|
|
94
100
|
except Exception as e:
|
|
95
101
|
return False, str(e)
|
|
96
102
|
|
|
@@ -225,8 +231,8 @@ class DiagnosticRunner:
|
|
|
225
231
|
is_user_home = False
|
|
226
232
|
try:
|
|
227
233
|
is_user_home = self.target_dir.resolve() == Path.home().resolve()
|
|
228
|
-
except
|
|
229
|
-
|
|
234
|
+
except OSError:
|
|
235
|
+
is_user_home = False
|
|
230
236
|
|
|
231
237
|
has_project_marker = any([
|
|
232
238
|
(self.target_dir / marker).exists() for marker in [
|
|
@@ -303,8 +309,8 @@ class DiagnosticRunner:
|
|
|
303
309
|
k, v = line.strip().split("=", 1)
|
|
304
310
|
if k.strip() not in os.environ:
|
|
305
311
|
os.environ[k.strip()] = v.strip().strip("'\"")
|
|
306
|
-
except
|
|
307
|
-
|
|
312
|
+
except OSError as err:
|
|
313
|
+
sys.stderr.write(f"Notice: .env read failed: {err}\n")
|
|
308
314
|
|
|
309
315
|
base = os.environ.get("BASE_URL", "").rstrip("/")
|
|
310
316
|
if not base:
|
|
@@ -328,7 +334,7 @@ class DiagnosticRunner:
|
|
|
328
334
|
ctx.verify_mode = ssl.CERT_NONE
|
|
329
335
|
|
|
330
336
|
req = urllib.request.Request(test_url, headers={'User-Agent': 'Mozilla/5.0'})
|
|
331
|
-
with urllib.request.urlopen(req, timeout=8, context=ctx) as resp:
|
|
337
|
+
with urllib.request.urlopen(req, timeout=8, context=ctx) as resp: # nosec B310
|
|
332
338
|
code = resp.getcode()
|
|
333
339
|
if code in (200, 301, 302):
|
|
334
340
|
self.log_check("Network / Server Base URL", "PASS", f"Connection successful to {test_url} (HTTP {code})")
|