bmad-plus 0.4.0 → 0.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.
Files changed (68) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/README.md +12 -56
  3. package/osint-agent-package/skills/bmad-osint-investigate/osint/SKILL.md +452 -452
  4. package/osint-agent-package/skills/bmad-osint-investigate/osint/assets/dossier-template.md +116 -116
  5. package/osint-agent-package/skills/bmad-osint-investigate/osint/references/content-extraction.md +100 -100
  6. package/osint-agent-package/skills/bmad-osint-investigate/osint/references/platforms.md +130 -130
  7. package/osint-agent-package/skills/bmad-osint-investigate/osint/references/psychoprofile.md +69 -69
  8. package/osint-agent-package/skills/bmad-osint-investigate/osint/references/tools.md +281 -281
  9. package/osint-agent-package/skills/bmad-osint-investigate/osint/scripts/mcp-client.py +136 -136
  10. package/package.json +1 -1
  11. package/readme-international/README.de.md +1 -1
  12. package/readme-international/README.es.md +1 -1
  13. package/readme-international/README.fr.md +1 -1
  14. package/tools/cli/commands/install.js +74 -46
  15. package/tools/cli/i18n.js +501 -0
  16. package/oveanet-pack/animated-website/DEPLOYMENT.md +0 -104
  17. package/oveanet-pack/animated-website/README.md +0 -63
  18. package/oveanet-pack/animated-website/agent/animated-website-agent.md +0 -325
  19. package/oveanet-pack/animated-website/agent.yaml +0 -63
  20. package/oveanet-pack/animated-website/templates/animated-website-workflow.md +0 -55
  21. package/oveanet-pack/seo-audit-360/DEPLOYMENT.md +0 -115
  22. package/oveanet-pack/seo-audit-360/README.md +0 -66
  23. package/oveanet-pack/seo-audit-360/SKILL.md +0 -171
  24. package/oveanet-pack/seo-audit-360/agent/seo-chief.md +0 -294
  25. package/oveanet-pack/seo-audit-360/agent/seo-judge.md +0 -241
  26. package/oveanet-pack/seo-audit-360/agent/seo-scout.md +0 -171
  27. package/oveanet-pack/seo-audit-360/agent.yaml +0 -70
  28. package/oveanet-pack/seo-audit-360/checklist.md +0 -140
  29. package/oveanet-pack/seo-audit-360/extensions/google-analytics/EXTENSION.md +0 -79
  30. package/oveanet-pack/seo-audit-360/extensions/google-analytics/ga4_client.py +0 -200
  31. package/oveanet-pack/seo-audit-360/extensions/google-analytics/requirements.txt +0 -4
  32. package/oveanet-pack/seo-audit-360/extensions/google-search-console/EXTENSION.md +0 -109
  33. package/oveanet-pack/seo-audit-360/extensions/google-search-console/gsc_client.py +0 -186
  34. package/oveanet-pack/seo-audit-360/extensions/google-search-console/requirements.txt +0 -4
  35. package/oveanet-pack/seo-audit-360/hooks/seo-check.sh +0 -95
  36. package/oveanet-pack/seo-audit-360/pagespeed-playbook.md +0 -320
  37. package/oveanet-pack/seo-audit-360/ref/audit-schema.json +0 -187
  38. package/oveanet-pack/seo-audit-360/ref/cwv-thresholds.md +0 -87
  39. package/oveanet-pack/seo-audit-360/ref/eeat-criteria.md +0 -123
  40. package/oveanet-pack/seo-audit-360/ref/geo-signals.md +0 -167
  41. package/oveanet-pack/seo-audit-360/ref/hreflang-rules.md +0 -153
  42. package/oveanet-pack/seo-audit-360/ref/quality-gates.md +0 -133
  43. package/oveanet-pack/seo-audit-360/ref/schema-catalog.md +0 -91
  44. package/oveanet-pack/seo-audit-360/ref/schema-templates.json +0 -356
  45. package/oveanet-pack/seo-audit-360/requirements.txt +0 -14
  46. package/oveanet-pack/seo-audit-360/scripts/__pycache__/seo_crawl.cpython-314.pyc +0 -0
  47. package/oveanet-pack/seo-audit-360/scripts/__pycache__/seo_parse.cpython-314.pyc +0 -0
  48. package/oveanet-pack/seo-audit-360/scripts/install.ps1 +0 -53
  49. package/oveanet-pack/seo-audit-360/scripts/install.sh +0 -48
  50. package/oveanet-pack/seo-audit-360/scripts/seo_apis.py +0 -464
  51. package/oveanet-pack/seo-audit-360/scripts/seo_crawl.py +0 -282
  52. package/oveanet-pack/seo-audit-360/scripts/seo_fetch.py +0 -231
  53. package/oveanet-pack/seo-audit-360/scripts/seo_parse.py +0 -255
  54. package/oveanet-pack/seo-audit-360/scripts/seo_report.py +0 -403
  55. package/oveanet-pack/seo-audit-360/scripts/seo_screenshot.py +0 -202
  56. package/oveanet-pack/seo-audit-360/templates/seo-audit-workflow.md +0 -241
  57. package/oveanet-pack/seo-audit-360/tests/__pycache__/test_crawl.cpython-314-pytest-9.0.2.pyc +0 -0
  58. package/oveanet-pack/seo-audit-360/tests/__pycache__/test_parse.cpython-314-pytest-9.0.2.pyc +0 -0
  59. package/oveanet-pack/seo-audit-360/tests/fixtures/sample_page.html +0 -62
  60. package/oveanet-pack/seo-audit-360/tests/test_apis.py +0 -75
  61. package/oveanet-pack/seo-audit-360/tests/test_crawl.py +0 -121
  62. package/oveanet-pack/seo-audit-360/tests/test_fetch.py +0 -70
  63. package/oveanet-pack/seo-audit-360/tests/test_parse.py +0 -184
  64. package/oveanet-pack/universal-backup/DEPLOYMENT.md +0 -80
  65. package/oveanet-pack/universal-backup/README.md +0 -58
  66. package/oveanet-pack/universal-backup/agent/backup-agent.md +0 -71
  67. package/oveanet-pack/universal-backup/agent.yaml +0 -45
  68. package/oveanet-pack/universal-backup/templates/backup-workflow.md +0 -51
@@ -1,109 +0,0 @@
1
- # Google Search Console Extension — BMAD+ SEO Engine
2
-
3
- > Author: Laurent Rochetta | BMAD+ SEO Engine v2.1
4
-
5
- ## Overview
6
-
7
- This extension connects the SEO Engine to Google Search Console API v3 for accessing real organic search performance data. Requires OAuth2 authentication with a Google Cloud project.
8
-
9
- ## Setup Guide
10
-
11
- ### 1. Create Google Cloud Project
12
- 1. Go to [Google Cloud Console](https://console.cloud.google.com)
13
- 2. Create a new project or select existing
14
- 3. Enable **Google Search Console API**
15
-
16
- ### 2. Create OAuth2 Credentials
17
- 1. Go to **APIs & Services > Credentials**
18
- 2. Click **Create Credentials > OAuth 2.0 Client ID**
19
- 3. Application type: **Desktop app**
20
- 4. Download the JSON → save as `credentials.json` in this directory
21
-
22
- ### 3. First Run
23
- ```bash
24
- python gsc_client.py --setup
25
- ```
26
- This opens a browser for OAuth consent. The refresh token is saved to `token.json` for subsequent runs.
27
-
28
- ### 4. Verify Access
29
- ```bash
30
- python gsc_client.py --sites
31
- ```
32
- Should list all verified Search Console properties.
33
-
34
- ## Commands
35
-
36
- ```bash
37
- # List verified sites
38
- python gsc_client.py --sites
39
-
40
- # Top queries (default: 28 days)
41
- python gsc_client.py --queries https://example.com --days 28
42
-
43
- # Top pages by organic traffic
44
- python gsc_client.py --pages https://example.com --days 28
45
-
46
- # Index coverage (errors, valid, excluded)
47
- python gsc_client.py --coverage https://example.com
48
-
49
- # Sitemap status
50
- python gsc_client.py --sitemaps https://example.com
51
-
52
- # Full export (all data, JSON)
53
- python gsc_client.py --all https://example.com --json > gsc-data.json
54
- ```
55
-
56
- ## Output Examples
57
-
58
- ### Queries
59
- ```
60
- Top Organic Queries (28 days):
61
- 1. "bmad framework" — Pos: 3.2, Clicks: 450, CTR: 12.3%, Imp: 3,658
62
- 2. "ai development tool" — Pos: 8.1, Clicks: 120, CTR: 3.5%, Imp: 3,428
63
- 3. "multi-agent coding" — Pos: 5.4, Clicks: 95, CTR: 7.8%, Imp: 1,218
64
- ```
65
-
66
- ### Coverage
67
- ```
68
- Index Coverage:
69
- ✅ Valid: 142 pages
70
- ⚠️ Valid with warnings: 8 pages
71
- ❌ Error: 3 pages
72
- ⛔ Excluded: 45 pages (noindex, canonical, etc.)
73
- ```
74
-
75
- ## Integration with SEO Engine
76
-
77
- When this extension is installed, the SKILL.md orchestrator can:
78
- - Include real organic data in Phase 4 scoring
79
- - Compare GSC impressions with crawled pages to find content gaps
80
- - Detect indexed pages with declining CTR → priority optimization targets
81
- - Cross-reference sitemap URLs with actually indexed pages
82
-
83
- ## Files
84
-
85
- | File | Purpose |
86
- |------|---------|
87
- | `EXTENSION.md` | This documentation |
88
- | `gsc_client.py` | OAuth2 flow + API calls |
89
- | `requirements.txt` | Python dependencies |
90
-
91
- ## Dependencies SUPPLÉMENTAIRES
92
-
93
- ```
94
- google-auth>=2.0.0
95
- google-auth-oauthlib>=1.0.0
96
- google-api-python-client>=2.0.0
97
- ```
98
-
99
- ## Security Notes
100
-
101
- - `credentials.json` — Contains client ID/secret. **Do not commit to Git.**
102
- - `token.json` — Contains refresh token. **Do not commit to Git.**
103
- - Add both to `.gitignore`
104
-
105
- ## Rate Limits
106
-
107
- - 1,200 queries per minute per project
108
- - 25,000 rows per request maximum
109
- - Data typically 2-3 days delayed
@@ -1,186 +0,0 @@
1
- #!/usr/bin/env python3
2
- """
3
- Google Search Console Client — OAuth2 API client for organic search data.
4
-
5
- Features:
6
- - OAuth2 flow with credential persistence
7
- - Query performance data (queries, pages, devices, countries)
8
- - Index coverage status
9
- - Sitemap submissions
10
-
11
- Author: Laurent Rochetta
12
- License: MIT
13
- """
14
-
15
- import argparse
16
- import json
17
- import os
18
- import sys
19
- from datetime import datetime, timedelta
20
-
21
- SCOPES = ["https://www.googleapis.com/auth/webmasters.readonly"]
22
- CREDENTIALS_FILE = os.path.join(os.path.dirname(__file__), "credentials.json")
23
- TOKEN_FILE = os.path.join(os.path.dirname(__file__), "token.json")
24
-
25
-
26
- def get_service():
27
- """Authenticate and return a Search Console service object."""
28
- try:
29
- from google.oauth2.credentials import Credentials
30
- from google_auth_oauthlib.flow import InstalledAppFlow
31
- from googleapiclient.discovery import build
32
- from google.auth.transport.requests import Request
33
- except ImportError:
34
- print(
35
- "Error: Missing dependencies. Install:\n"
36
- " pip install google-auth google-auth-oauthlib google-api-python-client",
37
- file=sys.stderr,
38
- )
39
- sys.exit(1)
40
-
41
- creds = None
42
- if os.path.exists(TOKEN_FILE):
43
- creds = Credentials.from_authorized_user_file(TOKEN_FILE, SCOPES)
44
-
45
- if not creds or not creds.valid:
46
- if creds and creds.expired and creds.refresh_token:
47
- creds.refresh(Request())
48
- else:
49
- if not os.path.exists(CREDENTIALS_FILE):
50
- print(
51
- f"Error: {CREDENTIALS_FILE} not found.\n"
52
- "Download OAuth2 credentials from Google Cloud Console.\n"
53
- "See EXTENSION.md for setup guide.",
54
- file=sys.stderr,
55
- )
56
- sys.exit(1)
57
- flow = InstalledAppFlow.from_client_secrets_file(CREDENTIALS_FILE, SCOPES)
58
- creds = flow.run_local_server(port=0)
59
-
60
- with open(TOKEN_FILE, "w") as f:
61
- f.write(creds.to_json())
62
-
63
- return build("searchconsole", "v1", credentials=creds)
64
-
65
-
66
- def list_sites(service):
67
- """List all verified Search Console properties."""
68
- result = service.sites().list().execute()
69
- sites = result.get("siteEntry", [])
70
- return [{"url": s["siteUrl"], "level": s["permissionLevel"]} for s in sites]
71
-
72
-
73
- def query_performance(service, site_url: str, days: int = 28, dimensions: list = None, row_limit: int = 25):
74
- """Query Search Analytics for organic performance data."""
75
- if dimensions is None:
76
- dimensions = ["query"]
77
-
78
- end_date = datetime.now().date()
79
- start_date = end_date - timedelta(days=days)
80
-
81
- body = {
82
- "startDate": start_date.isoformat(),
83
- "endDate": end_date.isoformat(),
84
- "dimensions": dimensions,
85
- "rowLimit": row_limit,
86
- "dataState": "all",
87
- }
88
-
89
- result = service.searchanalytics().query(siteUrl=site_url, body=body).execute()
90
- rows = result.get("rows", [])
91
-
92
- return [{
93
- "keys": row["keys"],
94
- "clicks": row["clicks"],
95
- "impressions": row["impressions"],
96
- "ctr": round(row["ctr"] * 100, 1),
97
- "position": round(row["position"], 1),
98
- } for row in rows]
99
-
100
-
101
- def get_sitemaps(service, site_url: str):
102
- """Get sitemap submission status."""
103
- result = service.sitemaps().list(siteUrl=site_url).execute()
104
- sitemaps = result.get("sitemap", [])
105
- return [{
106
- "path": s["path"],
107
- "type": s.get("type", ""),
108
- "submitted": s.get("lastSubmitted", ""),
109
- "warnings": s.get("warnings", 0),
110
- "errors": s.get("errors", 0),
111
- } for s in sitemaps]
112
-
113
-
114
- # ── CLI ────────────────────────────────────────────────────────────
115
-
116
- def main():
117
- parser = argparse.ArgumentParser(
118
- description="Google Search Console Client (BMAD+ SEO Engine)"
119
- )
120
- parser.add_argument("site", nargs="?", help="Site URL (e.g. https://example.com)")
121
- parser.add_argument("--setup", action="store_true", help="Run OAuth2 setup flow")
122
- parser.add_argument("--sites", action="store_true", help="List verified sites")
123
- parser.add_argument("--queries", action="store_true", help="Top queries")
124
- parser.add_argument("--pages", action="store_true", help="Top pages")
125
- parser.add_argument("--sitemaps", action="store_true", help="Sitemap status")
126
- parser.add_argument("--all", action="store_true", help="All data")
127
- parser.add_argument("--days", type=int, default=28, help="Days lookback (default: 28)")
128
- parser.add_argument("--limit", type=int, default=25, help="Max rows (default: 25)")
129
- parser.add_argument("--json", "-j", action="store_true", help="Output as JSON")
130
-
131
- args = parser.parse_args()
132
-
133
- service = get_service()
134
-
135
- if args.setup:
136
- print("✅ OAuth2 setup complete. Token saved.")
137
- return
138
-
139
- if args.sites:
140
- sites = list_sites(service)
141
- if args.json:
142
- print(json.dumps(sites, indent=2))
143
- else:
144
- print("\nVerified Sites:")
145
- for s in sites:
146
- print(f" {s['url']} ({s['level']})")
147
- return
148
-
149
- if not args.site:
150
- parser.print_help()
151
- return
152
-
153
- if args.queries or args.all:
154
- data = query_performance(service, args.site, args.days, ["query"], args.limit)
155
- if args.json:
156
- print(json.dumps({"queries": data}, indent=2))
157
- else:
158
- print(f"\nTop Queries ({args.days} days):")
159
- for i, row in enumerate(data, 1):
160
- q = row["keys"][0]
161
- print(f" {i:2}. \"{q[:50]}\" — Pos: {row['position']}, "
162
- f"Clicks: {row['clicks']:,}, CTR: {row['ctr']}%, Imp: {row['impressions']:,}")
163
-
164
- if args.pages or args.all:
165
- data = query_performance(service, args.site, args.days, ["page"], args.limit)
166
- if args.json:
167
- print(json.dumps({"pages": data}, indent=2))
168
- else:
169
- print(f"\nTop Pages ({args.days} days):")
170
- for i, row in enumerate(data, 1):
171
- page = row["keys"][0]
172
- print(f" {i:2}. {page[:60]} — Clicks: {row['clicks']:,}, CTR: {row['ctr']}%")
173
-
174
- if args.sitemaps or args.all:
175
- data = get_sitemaps(service, args.site)
176
- if args.json:
177
- print(json.dumps({"sitemaps": data}, indent=2))
178
- else:
179
- print(f"\nSitemaps:")
180
- for s in data:
181
- status = "✅" if s["errors"] == 0 else "❌"
182
- print(f" {status} {s['path']} (type: {s['type']}, errors: {s['errors']})")
183
-
184
-
185
- if __name__ == "__main__":
186
- main()
@@ -1,4 +0,0 @@
1
- # Google Search Console Extension — Dependencies
2
- google-auth>=2.0.0
3
- google-auth-oauthlib>=1.0.0
4
- google-api-python-client>=2.0.0
@@ -1,95 +0,0 @@
1
- #!/bin/bash
2
- # SEO Pre-Commit Hook — Catches common SEO issues before commit.
3
- # Install: cp hooks/seo-check.sh .git/hooks/pre-commit && chmod +x .git/hooks/pre-commit
4
- #
5
- # Author: Laurent Rochetta | BMAD+ SEO Engine
6
-
7
- ERRORS=0
8
- WARNINGS=0
9
-
10
- echo "🔎 BMAD+ SEO Pre-Commit Check..."
11
-
12
- # Only check staged HTML files
13
- HTML_FILES=$(git diff --cached --name-only --diff-filter=ACM | grep -iE '\.(html|htm|php|jsx|tsx)$')
14
-
15
- if [ -z "$HTML_FILES" ]; then
16
- echo " No HTML files staged, skipping SEO check."
17
- exit 0
18
- fi
19
-
20
- for FILE in $HTML_FILES; do
21
- # Skip node_modules and vendor
22
- if echo "$FILE" | grep -qE '(node_modules|vendor|dist|build|\.min\.)'; then
23
- continue
24
- fi
25
-
26
- CONTENT=$(git show ":$FILE" 2>/dev/null)
27
- if [ -z "$CONTENT" ]; then
28
- continue
29
- fi
30
-
31
- # Check 1: Missing <title> tag
32
- if ! echo "$CONTENT" | grep -qi '<title'; then
33
- echo " 🔴 $FILE — Missing <title> tag"
34
- ERRORS=$((ERRORS + 1))
35
- fi
36
-
37
- # Check 2: Empty <title> tag
38
- if echo "$CONTENT" | grep -qiE '<title>\s*</title>'; then
39
- echo " 🔴 $FILE — Empty <title> tag"
40
- ERRORS=$((ERRORS + 1))
41
- fi
42
-
43
- # Check 3: Missing meta description
44
- if ! echo "$CONTENT" | grep -qi 'name="description"'; then
45
- echo " 🟠 $FILE — Missing <meta name=\"description\">"
46
- WARNINGS=$((WARNINGS + 1))
47
- fi
48
-
49
- # Check 4: Images without alt attribute
50
- IMG_NO_ALT=$(echo "$CONTENT" | grep -ciE '<img[^>]*(?!alt)[^>]*>' 2>/dev/null || echo "0")
51
- # More reliable: count <img> without alt
52
- TOTAL_IMGS=$(echo "$CONTENT" | grep -ci '<img' 2>/dev/null || echo "0")
53
- IMGS_WITH_ALT=$(echo "$CONTENT" | grep -ci '<img[^>]*alt=' 2>/dev/null || echo "0")
54
- MISSING_ALT=$((TOTAL_IMGS - IMGS_WITH_ALT))
55
-
56
- if [ "$MISSING_ALT" -gt 0 ]; then
57
- echo " 🟠 $FILE — $MISSING_ALT image(s) without alt attribute"
58
- WARNINGS=$((WARNINGS + 1))
59
- fi
60
-
61
- # Check 5: Multiple H1 tags
62
- H1_COUNT=$(echo "$CONTENT" | grep -ci '<h1' 2>/dev/null || echo "0")
63
- if [ "$H1_COUNT" -gt 1 ]; then
64
- echo " 🟡 $FILE — Multiple H1 tags ($H1_COUNT found, should be 1)"
65
- WARNINGS=$((WARNINGS + 1))
66
- fi
67
-
68
- # Check 6: No H1 tag at all
69
- if [ "$H1_COUNT" -eq 0 ]; then
70
- echo " 🟠 $FILE — No H1 tag found"
71
- WARNINGS=$((WARNINGS + 1))
72
- fi
73
-
74
- # Check 7: "Click here" or "Learn more" anchor text
75
- BAD_ANCHORS=$(echo "$CONTENT" | grep -ciE '>click here<|>learn more<|>read more<|>here<' 2>/dev/null || echo "0")
76
- if [ "$BAD_ANCHORS" -gt 0 ]; then
77
- echo " 🟡 $FILE — $BAD_ANCHORS link(s) with generic anchor text (\"click here\", \"learn more\")"
78
- WARNINGS=$((WARNINGS + 1))
79
- fi
80
- done
81
-
82
- echo ""
83
- echo " Results: $ERRORS error(s), $WARNINGS warning(s)"
84
-
85
- if [ "$ERRORS" -gt 0 ]; then
86
- echo " ❌ Commit blocked — fix critical SEO issues first!"
87
- exit 1
88
- else
89
- if [ "$WARNINGS" -gt 0 ]; then
90
- echo " ⚠️ Commit allowed with warnings — consider fixing these issues."
91
- else
92
- echo " ✅ All SEO checks passed!"
93
- fi
94
- exit 0
95
- fi