wordpress-agent-kit 0.4.0 → 0.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.
Files changed (153) hide show
  1. package/.agents/skills/wp-bootstrap/SKILL.md +314 -0
  2. package/.agents/skills/wp-bootstrap/references/composer-setup.md +275 -0
  3. package/.agents/skills/wp-bootstrap/references/monorepo-patterns.md +184 -0
  4. package/.agents/skills/wp-bootstrap/scripts/bootstrap.sh +151 -0
  5. package/.agents/skills/wp-bootstrap/scripts/detect-structure.mjs +466 -0
  6. package/.agents/skills/wp-bootstrap/scripts/package-wp.sh +173 -0
  7. package/.agents/skills/wp-bootstrap/scripts/playground-start.sh +148 -0
  8. package/.agents/skills/wp-bootstrap/scripts/playground-verify.sh +165 -0
  9. package/.agents/skills/wp-bootstrap/scripts/setup-github.sh +417 -0
  10. package/{.github → .agents}/skills/wp-wpcli-and-ops/SKILL.md +11 -9
  11. package/.agents/skills/wp-wpengine/SKILL.md +462 -0
  12. package/.agents/skills/wp-wpengine/references/ci-gate.md +469 -0
  13. package/.agents/skills/wp-wpengine/references/github-actions-deploy.md +743 -0
  14. package/.agents/skills/wp-wpengine/scripts/ci-gate.sh +118 -0
  15. package/.agents/skills/wp-wpengine/scripts/wpe-check.sh +89 -0
  16. package/.agents/skills/wp-wpengine/scripts/wpe-preflight.sh +104 -0
  17. package/.github/agents/wp-architect.agent.md +1 -2
  18. package/.github/copilot-instructions.md +1 -1
  19. package/.github/instructions/wordpress-workflow.instructions.md +3 -3
  20. package/AGENTS.md +22 -10
  21. package/AGENTS.template.md +20 -10
  22. package/README.md +89 -85
  23. package/dist/cli.js +7 -1
  24. package/dist/commands/bootstrap.js +105 -0
  25. package/dist/commands/clean-skills.js +64 -0
  26. package/dist/commands/setup.js +6 -2
  27. package/dist/commands/sync-skills.js +3 -0
  28. package/dist/lib/api.js +165 -5
  29. package/dist/lib/bootstrap.js +352 -0
  30. package/dist/lib/installer.js +166 -2
  31. package/extensions/wp-agent-kit/index.ts +325 -10
  32. package/package.json +10 -14
  33. package/skills-custom/wp-bootstrap/SKILL.md +314 -0
  34. package/skills-custom/wp-bootstrap/references/composer-setup.md +275 -0
  35. package/skills-custom/wp-bootstrap/references/monorepo-patterns.md +184 -0
  36. package/skills-custom/wp-bootstrap/scripts/bootstrap.sh +151 -0
  37. package/skills-custom/wp-bootstrap/scripts/detect-structure.mjs +466 -0
  38. package/skills-custom/wp-bootstrap/scripts/package-wp.sh +173 -0
  39. package/skills-custom/wp-bootstrap/scripts/playground-start.sh +148 -0
  40. package/skills-custom/wp-bootstrap/scripts/playground-verify.sh +165 -0
  41. package/skills-custom/wp-bootstrap/scripts/setup-github.sh +417 -0
  42. package/skills-custom/wp-wpengine/SKILL.md +362 -27
  43. package/skills-custom/wp-wpengine/references/ci-gate.md +469 -0
  44. package/skills-custom/wp-wpengine/references/github-actions-deploy.md +743 -0
  45. package/skills-custom/wp-wpengine/scripts/ci-gate.sh +118 -0
  46. package/skills-custom/wp-wpengine/scripts/wpe-check.sh +89 -0
  47. package/skills-custom/wp-wpengine/scripts/wpe-preflight.sh +104 -0
  48. package/.github/skills/wp-wpengine/SKILL.md +0 -127
  49. package/.github/workflows/ci.yml +0 -44
  50. package/.husky/pre-commit +0 -7
  51. package/CLI_REVIEW.md +0 -250
  52. package/biome.json +0 -39
  53. /package/{.github → .agents}/skills/blueprint/SKILL.md +0 -0
  54. /package/{.github → .agents}/skills/wordpress-router/SKILL.md +0 -0
  55. /package/{.github → .agents}/skills/wordpress-router/references/decision-tree.md +0 -0
  56. /package/{.github → .agents}/skills/wp-abilities-api/SKILL.md +0 -0
  57. /package/{.github → .agents}/skills/wp-abilities-api/references/delegate-helper-pattern.md +0 -0
  58. /package/{.github → .agents}/skills/wp-abilities-api/references/domain-vs-projection.md +0 -0
  59. /package/{.github → .agents}/skills/wp-abilities-api/references/error-code-vocabulary.md +0 -0
  60. /package/{.github → .agents}/skills/wp-abilities-api/references/grouping-heuristic.md +0 -0
  61. /package/{.github → .agents}/skills/wp-abilities-api/references/input-schema-gotchas.md +0 -0
  62. /package/{.github → .agents}/skills/wp-abilities-api/references/php-registration.md +0 -0
  63. /package/{.github → .agents}/skills/wp-abilities-api/references/plugin-family-patterns.md +0 -0
  64. /package/{.github → .agents}/skills/wp-abilities-api/references/rest-api.md +0 -0
  65. /package/{.github → .agents}/skills/wp-abilities-api/references/shared-core-service.md +0 -0
  66. /package/{.github → .agents}/skills/wp-abilities-audit/SKILL.md +0 -0
  67. /package/{.github → .agents}/skills/wp-abilities-audit/references/audit-schema.md +0 -0
  68. /package/{.github → .agents}/skills/wp-abilities-audit/references/capability-gate-tracing.md +0 -0
  69. /package/{.github → .agents}/skills/wp-abilities-audit/references/controller-enumeration.md +0 -0
  70. /package/{.github → .agents}/skills/wp-abilities-verify/SKILL.md +0 -0
  71. /package/{.github → .agents}/skills/wp-abilities-verify/references/annotation-correctness.md +0 -0
  72. /package/{.github → .agents}/skills/wp-abilities-verify/references/audit-schema-validation.md +0 -0
  73. /package/{.github → .agents}/skills/wp-abilities-verify/references/permission-roundtrip.md +0 -0
  74. /package/{.github → .agents}/skills/wp-abilities-verify/references/runtime-harness.md +0 -0
  75. /package/{.github → .agents}/skills/wp-abilities-verify/references/schema-lints.md +0 -0
  76. /package/{.github → .agents}/skills/wp-abilities-verify/references/static-enumeration.md +0 -0
  77. /package/{.github → .agents}/skills/wp-block-development/SKILL.md +0 -0
  78. /package/{.github → .agents}/skills/wp-block-development/references/attributes-and-serialization.md +0 -0
  79. /package/{.github → .agents}/skills/wp-block-development/references/block-json.md +0 -0
  80. /package/{.github → .agents}/skills/wp-block-development/references/creating-new-blocks.md +0 -0
  81. /package/{.github → .agents}/skills/wp-block-development/references/debugging.md +0 -0
  82. /package/{.github → .agents}/skills/wp-block-development/references/deprecations.md +0 -0
  83. /package/{.github → .agents}/skills/wp-block-development/references/dynamic-rendering.md +0 -0
  84. /package/{.github → .agents}/skills/wp-block-development/references/inner-blocks.md +0 -0
  85. /package/{.github → .agents}/skills/wp-block-development/references/registration.md +0 -0
  86. /package/{.github → .agents}/skills/wp-block-development/references/supports-and-wrappers.md +0 -0
  87. /package/{.github → .agents}/skills/wp-block-development/references/tooling-and-testing.md +0 -0
  88. /package/{.github → .agents}/skills/wp-block-development/scripts/list_blocks.mjs +0 -0
  89. /package/{.github → .agents}/skills/wp-block-themes/SKILL.md +0 -0
  90. /package/{.github → .agents}/skills/wp-block-themes/references/creating-new-block-theme.md +0 -0
  91. /package/{.github → .agents}/skills/wp-block-themes/references/debugging.md +0 -0
  92. /package/{.github → .agents}/skills/wp-block-themes/references/patterns.md +0 -0
  93. /package/{.github → .agents}/skills/wp-block-themes/references/style-variations.md +0 -0
  94. /package/{.github → .agents}/skills/wp-block-themes/references/templates-and-parts.md +0 -0
  95. /package/{.github → .agents}/skills/wp-block-themes/references/theme-json.md +0 -0
  96. /package/{.github → .agents}/skills/wp-block-themes/scripts/detect_block_themes.mjs +0 -0
  97. /package/{.github → .agents}/skills/wp-interactivity-api/SKILL.md +0 -0
  98. /package/{.github → .agents}/skills/wp-interactivity-api/references/debugging.md +0 -0
  99. /package/{.github → .agents}/skills/wp-interactivity-api/references/directives-quickref.md +0 -0
  100. /package/{.github → .agents}/skills/wp-interactivity-api/references/server-side-rendering.md +0 -0
  101. /package/{.github → .agents}/skills/wp-performance/SKILL.md +0 -0
  102. /package/{.github → .agents}/skills/wp-performance/references/autoload-options.md +0 -0
  103. /package/{.github → .agents}/skills/wp-performance/references/cron.md +0 -0
  104. /package/{.github → .agents}/skills/wp-performance/references/database.md +0 -0
  105. /package/{.github → .agents}/skills/wp-performance/references/http-api.md +0 -0
  106. /package/{.github → .agents}/skills/wp-performance/references/measurement.md +0 -0
  107. /package/{.github → .agents}/skills/wp-performance/references/object-cache.md +0 -0
  108. /package/{.github → .agents}/skills/wp-performance/references/query-monitor-headless.md +0 -0
  109. /package/{.github → .agents}/skills/wp-performance/references/server-timing.md +0 -0
  110. /package/{.github → .agents}/skills/wp-performance/references/wp-cli-doctor.md +0 -0
  111. /package/{.github → .agents}/skills/wp-performance/references/wp-cli-profile.md +0 -0
  112. /package/{.github → .agents}/skills/wp-performance/scripts/perf_inspect.mjs +0 -0
  113. /package/{.github → .agents}/skills/wp-phpstan/SKILL.md +0 -0
  114. /package/{.github → .agents}/skills/wp-phpstan/references/configuration.md +0 -0
  115. /package/{.github → .agents}/skills/wp-phpstan/references/third-party-classes.md +0 -0
  116. /package/{.github → .agents}/skills/wp-phpstan/references/wordpress-annotations.md +0 -0
  117. /package/{.github → .agents}/skills/wp-phpstan/scripts/phpstan_inspect.mjs +0 -0
  118. /package/{.github → .agents}/skills/wp-playground/SKILL.md +0 -0
  119. /package/{.github → .agents}/skills/wp-playground/references/blueprints.md +0 -0
  120. /package/{.github → .agents}/skills/wp-playground/references/cli-commands.md +0 -0
  121. /package/{.github → .agents}/skills/wp-playground/references/debugging.md +0 -0
  122. /package/{.github → .agents}/skills/wp-playground/references/e2e-playwright.md +0 -0
  123. /package/{.github → .agents}/skills/wp-plugin-development/SKILL.md +0 -0
  124. /package/{.github → .agents}/skills/wp-plugin-development/references/data-and-cron.md +0 -0
  125. /package/{.github → .agents}/skills/wp-plugin-development/references/debugging.md +0 -0
  126. /package/{.github → .agents}/skills/wp-plugin-development/references/lifecycle.md +0 -0
  127. /package/{.github → .agents}/skills/wp-plugin-development/references/security.md +0 -0
  128. /package/{.github → .agents}/skills/wp-plugin-development/references/settings-api.md +0 -0
  129. /package/{.github → .agents}/skills/wp-plugin-development/references/structure.md +0 -0
  130. /package/{.github → .agents}/skills/wp-plugin-development/scripts/detect_plugins.mjs +0 -0
  131. /package/{.github → .agents}/skills/wp-plugin-directory-guidelines/SKILL.md +0 -0
  132. /package/{.github → .agents}/skills/wp-plugin-directory-guidelines/references/gpl-compliance.md +0 -0
  133. /package/{.github → .agents}/skills/wp-plugin-directory-guidelines/references/guideline-review-checklist.md +0 -0
  134. /package/{.github → .agents}/skills/wp-plugin-directory-guidelines/references/naming-rules.md +0 -0
  135. /package/{.github → .agents}/skills/wp-project-triage/SKILL.md +0 -0
  136. /package/{.github → .agents}/skills/wp-project-triage/references/triage.schema.json +0 -0
  137. /package/{.github → .agents}/skills/wp-project-triage/scripts/detect_wp_project.mjs +0 -0
  138. /package/{.github → .agents}/skills/wp-rest-api/SKILL.md +0 -0
  139. /package/{.github → .agents}/skills/wp-rest-api/references/authentication.md +0 -0
  140. /package/{.github → .agents}/skills/wp-rest-api/references/custom-content-types.md +0 -0
  141. /package/{.github → .agents}/skills/wp-rest-api/references/discovery-and-params.md +0 -0
  142. /package/{.github → .agents}/skills/wp-rest-api/references/responses-and-fields.md +0 -0
  143. /package/{.github → .agents}/skills/wp-rest-api/references/routes-and-endpoints.md +0 -0
  144. /package/{.github → .agents}/skills/wp-rest-api/references/schema.md +0 -0
  145. /package/{.github → .agents}/skills/wp-wpcli-and-ops/references/automation.md +0 -0
  146. /package/{.github → .agents}/skills/wp-wpcli-and-ops/references/cron-and-cache.md +0 -0
  147. /package/{.github → .agents}/skills/wp-wpcli-and-ops/references/debugging.md +0 -0
  148. /package/{.github → .agents}/skills/wp-wpcli-and-ops/references/multisite.md +0 -0
  149. /package/{.github → .agents}/skills/wp-wpcli-and-ops/references/packages-and-updates.md +0 -0
  150. /package/{.github → .agents}/skills/wp-wpcli-and-ops/references/safety.md +0 -0
  151. /package/{.github → .agents}/skills/wp-wpcli-and-ops/references/search-replace.md +0 -0
  152. /package/{.github → .agents}/skills/wp-wpcli-and-ops/scripts/wpcli_inspect.mjs +0 -0
  153. /package/{.github → .agents}/skills/wpds/SKILL.md +0 -0
@@ -0,0 +1,417 @@
1
+ #!/usr/bin/env bash
2
+ # setup-github.sh — configure GitHub repo for WP Engine CI/CD using the gh CLI.
3
+ #
4
+ # Checks authentication, reports missing secrets, sets them interactively or
5
+ # from provided values, and configures branch protection for deploy branches.
6
+ #
7
+ # Usage:
8
+ # bash .agents/skills/wp-bootstrap/scripts/setup-github.sh [OPTIONS]
9
+ #
10
+ # Options:
11
+ # --check-only Report status without making any changes (default if no --set-*)
12
+ # --set-secrets Interactively set missing WP Engine secrets
13
+ # --set-protection Configure branch protection for main/staging/develop
14
+ # --set-all Set secrets + branch protection
15
+ # --wpe-key=<file> Path to WP Engine SSH private key (default: ~/.ssh/wpengine_ed25519)
16
+ # --wpe-prod=<slug> WP Engine production install slug
17
+ # --wpe-staging=<slug> WP Engine staging install slug
18
+ # --wpe-dev=<slug> WP Engine dev install slug
19
+ # --no-confirm Skip confirmation prompts (use with care)
20
+ #
21
+ # Requires: gh CLI installed and authenticated (gh auth login)
22
+ #
23
+ # Exit codes:
24
+ # 0 All checks passed / actions completed
25
+ # 1 Error or user cancelled
26
+ # 2 gh CLI not installed or not authenticated
27
+
28
+ set -uo pipefail
29
+
30
+ # ── Parse args ────────────────────────────────────────────────────────────────
31
+ CHECK_ONLY=true
32
+ SET_SECRETS=false
33
+ SET_PROTECTION=false
34
+ WPE_KEY_FILE="${HOME}/.ssh/wpengine_ed25519"
35
+ WPE_PROD=""
36
+ WPE_STAGING=""
37
+ WPE_DEV=""
38
+ NO_CONFIRM=false
39
+
40
+ for arg in "$@"; do
41
+ case "$arg" in
42
+ --check-only) CHECK_ONLY=true ;;
43
+ --set-secrets) SET_SECRETS=true; CHECK_ONLY=false ;;
44
+ --set-protection) SET_PROTECTION=true; CHECK_ONLY=false ;;
45
+ --set-all) SET_SECRETS=true; SET_PROTECTION=true; CHECK_ONLY=false ;;
46
+ --wpe-key=*) WPE_KEY_FILE="${arg#--wpe-key=}" ;;
47
+ --wpe-prod=*) WPE_PROD="${arg#--wpe-prod=}" ;;
48
+ --wpe-staging=*) WPE_STAGING="${arg#--wpe-staging=}" ;;
49
+ --wpe-dev=*) WPE_DEV="${arg#--wpe-dev=}" ;;
50
+ --no-confirm) NO_CONFIRM=true ;;
51
+ esac
52
+ done
53
+
54
+ # ── Helpers ───────────────────────────────────────────────────────────────────
55
+ ok() { printf ' \033[32m✓\033[0m %s\n' "$*"; }
56
+ fail() { printf ' \033[31m✗\033[0m %s\n' "$*" >&2; }
57
+ warn() { printf ' \033[33m⚠\033[0m %s\n' "$*"; }
58
+ info() { printf ' \033[34m→\033[0m %s\n' "$*"; }
59
+ sep() { printf '\n\033[1m── %s\033[0m\n' "$*"; }
60
+
61
+ confirm() {
62
+ local prompt="${1} [y/N] "
63
+ $NO_CONFIRM && { echo "(auto-confirmed)"; return 0; }
64
+ read -r -p "$prompt" ans
65
+ [[ "${ans,,}" == "y" || "${ans,,}" == "yes" ]]
66
+ }
67
+
68
+ # ── 1. Check gh CLI ───────────────────────────────────────────────────────────
69
+ sep "GitHub CLI check"
70
+
71
+ if ! command -v gh >/dev/null 2>&1; then
72
+ fail "gh CLI not installed."
73
+ echo " Install: https://cli.github.com"
74
+ echo " macOS: brew install gh"
75
+ echo " Linux: sudo apt install gh (or see above URL)"
76
+ exit 2
77
+ fi
78
+ ok "gh $(gh --version | head -1 | awk '{print $3}')"
79
+
80
+ # ── 2. Check authentication ────────────────────────────────────────────────────
81
+ sep "Authentication"
82
+
83
+ AUTH_STATUS=$(gh auth status 2>&1)
84
+ if ! echo "$AUTH_STATUS" | grep -q "Logged in to github.com"; then
85
+ fail "Not authenticated. Run: gh auth login"
86
+ exit 2
87
+ fi
88
+
89
+ ACCOUNT=$(echo "$AUTH_STATUS" | grep -o 'account [^ ]*' | awk '{print $2}' | head -1)
90
+ ok "Authenticated as @${ACCOUNT}"
91
+
92
+ # ── 3. Detect repo ────────────────────────────────────────────────────────────
93
+ sep "Repository"
94
+
95
+ ORIGIN=$(git remote get-url origin 2>/dev/null || echo "")
96
+ if [ -z "$ORIGIN" ]; then
97
+ fail "No 'origin' remote found. Is this a git repo with a GitHub remote?"
98
+ exit 1
99
+ fi
100
+
101
+ # Parse owner/repo from SSH or HTTPS URL
102
+ if [[ "$ORIGIN" =~ git@github\.com[:/]([^/]+)/([^.]+)(\.git)?$ ]]; then
103
+ OWNER="${BASH_REMATCH[1]}"
104
+ REPO="${BASH_REMATCH[2]}"
105
+ elif [[ "$ORIGIN" =~ https?://github\.com/([^/]+)/([^/.]+) ]]; then
106
+ OWNER="${BASH_REMATCH[1]}"
107
+ REPO="${BASH_REMATCH[2]}"
108
+ else
109
+ fail "Cannot parse GitHub owner/repo from remote: $ORIGIN"
110
+ exit 1
111
+ fi
112
+
113
+ # Verify repo is accessible
114
+ REPO_INFO=$(gh repo view "${OWNER}/${REPO}" --json name,owner,url,defaultBranchRef,visibility 2>&1)
115
+ if ! echo "$REPO_INFO" | grep -q '"name"'; then
116
+ fail "Cannot access repo ${OWNER}/${REPO}. Check permissions."
117
+ exit 1
118
+ fi
119
+
120
+ VISIBILITY=$(echo "$REPO_INFO" | python3 -c "import sys,json; print(json.load(sys.stdin)['visibility'])" 2>/dev/null || echo "unknown")
121
+ DEFAULT_BRANCH=$(echo "$REPO_INFO" | python3 -c "import sys,json; print(json.load(sys.stdin)['defaultBranchRef']['name'])" 2>/dev/null || echo "main")
122
+ REPO_URL=$(echo "$REPO_INFO" | python3 -c "import sys,json; print(json.load(sys.stdin)['url'])" 2>/dev/null || echo "")
123
+
124
+ ok "${OWNER}/${REPO} (${VISIBILITY,,}) — ${REPO_URL}"
125
+ info "Default branch: ${DEFAULT_BRANCH}"
126
+
127
+ # ── 4. Check secrets ──────────────────────────────────────────────────────────
128
+ sep "GitHub Secrets"
129
+
130
+ EXISTING_JSON=$(gh secret list --repo "${OWNER}/${REPO}" --json name 2>/dev/null || echo "[]")
131
+ EXISTING_SECRETS=$(echo "$EXISTING_JSON" | python3 -c "
132
+ import sys,json
133
+ secrets = json.load(sys.stdin)
134
+ for s in secrets: print(s['name'])
135
+ " 2>/dev/null || echo "")
136
+
137
+ # Define required secrets and their descriptions
138
+ declare -A SECRET_DESC
139
+ SECRET_DESC[WPE_SSH_KEY]="WP Engine SSH private key (contents of wpengine_ed25519)"
140
+ SECRET_DESC[WPE_SSH_KNOWN_HOSTS]="Known hosts for git.wpengine.com + ssh.wpengine.net"
141
+ SECRET_DESC[WPE_PROD_INSTALL]="Production install slug (e.g. mysite)"
142
+ SECRET_DESC[WPE_PROD_GIT_URL]="Production git push URL from WPE portal"
143
+ SECRET_DESC[WPE_STAGING_INSTALL]="Staging install slug (e.g. mysitestg)"
144
+ SECRET_DESC[WPE_STAGING_GIT_URL]="Staging git push URL from WPE portal"
145
+ SECRET_DESC[WPE_DEV_INSTALL]="Development install slug (e.g. mysitedev)"
146
+ SECRET_DESC[WPE_DEV_GIT_URL]="Development git push URL from WPE portal"
147
+ SECRET_DESC[WPE_API_USER]="WP Engine API username (from my.wpengine.com/api_access)"
148
+ SECRET_DESC[WPE_API_PASSWORD]="WP Engine API password"
149
+ SECRET_DESC[SLACK_WEBHOOK_URL]="Slack incoming webhook URL (optional)"
150
+
151
+ REQUIRED_SECRETS=(
152
+ WPE_SSH_KEY WPE_SSH_KNOWN_HOSTS
153
+ WPE_PROD_INSTALL WPE_PROD_GIT_URL
154
+ WPE_STAGING_INSTALL WPE_STAGING_GIT_URL
155
+ WPE_DEV_INSTALL WPE_DEV_GIT_URL
156
+ WPE_API_USER WPE_API_PASSWORD
157
+ )
158
+
159
+ MISSING_SECRETS=()
160
+ for secret in "${REQUIRED_SECRETS[@]}"; do
161
+ if echo "$EXISTING_SECRETS" | grep -qx "$secret"; then
162
+ ok "$secret"
163
+ else
164
+ warn "$secret — MISSING"
165
+ MISSING_SECRETS+=("$secret")
166
+ fi
167
+ done
168
+
169
+ # Optional
170
+ if echo "$EXISTING_SECRETS" | grep -qx "SLACK_WEBHOOK_URL"; then
171
+ ok "SLACK_WEBHOOK_URL (optional)"
172
+ else
173
+ info "SLACK_WEBHOOK_URL — not set (optional)"
174
+ fi
175
+
176
+ echo ""
177
+ if [ "${#MISSING_SECRETS[@]}" -eq 0 ]; then
178
+ ok "All required secrets are set ✓"
179
+ else
180
+ warn "${#MISSING_SECRETS[@]} secret(s) missing — run with --set-secrets to configure"
181
+ fi
182
+
183
+ # ── 5. Set missing secrets ────────────────────────────────────────────────────
184
+ if $SET_SECRETS && [ "${#MISSING_SECRETS[@]}" -gt 0 ]; then
185
+ sep "Setting missing secrets"
186
+
187
+ for secret in "${MISSING_SECRETS[@]}"; do
188
+ echo ""
189
+ info "Setting: ${secret}"
190
+ info "Purpose: ${SECRET_DESC[$secret]}"
191
+
192
+ VALUE=""
193
+
194
+ case "$secret" in
195
+ WPE_SSH_KEY)
196
+ if [ -f "$WPE_KEY_FILE" ]; then
197
+ info "Reading from $WPE_KEY_FILE"
198
+ if confirm " Set WPE_SSH_KEY from $WPE_KEY_FILE?"; then
199
+ VALUE=$(cat "$WPE_KEY_FILE")
200
+ fi
201
+ else
202
+ warn "Key file not found: $WPE_KEY_FILE"
203
+ info "Alternatives:"
204
+ info " 1. op read 'op://Employee/wpengine_ed25519/private key' > ~/.ssh/wpengine_ed25519"
205
+ info " 2. Paste the key manually below (enter blank line when done)"
206
+ if confirm " Enter key manually?"; then
207
+ LINES=()
208
+ echo " Paste private key (empty line to finish):"
209
+ while IFS= read -r line; do
210
+ [ -z "$line" ] && break
211
+ LINES+=("$line")
212
+ done
213
+ VALUE=$(printf '%s\n' "${LINES[@]}")
214
+ fi
215
+ fi
216
+ ;;
217
+
218
+ WPE_SSH_KNOWN_HOSTS)
219
+ info "Generating from ssh-keyscan..."
220
+ VALUE=$(
221
+ {
222
+ # git push host — RSA key
223
+ ssh-keyscan -t rsa git.wpengine.com 2>/dev/null
224
+ # Include hashed entry for git.wpengine.com too
225
+ ssh-keyscan -H git.wpengine.com 2>/dev/null
226
+ # Note: SSH gateway subdomains ({install}.ssh.wpengine.net) use
227
+ # StrictHostKeyChecking=accept-new in the workflow SSH config,
228
+ # so they don't need pre-scanned entries here.
229
+ }
230
+ )
231
+ if [ -n "$VALUE" ]; then
232
+ info "Generated $(echo "$VALUE" | wc -l) known_hosts entries"
233
+ info "Gateway subdomains auto-accepted via StrictHostKeyChecking=accept-new"
234
+ confirm " Set WPE_SSH_KNOWN_HOSTS?" && true || VALUE=""
235
+ else
236
+ warn "ssh-keyscan failed — check network connectivity"
237
+ fi
238
+ ;;
239
+
240
+ WPE_PROD_INSTALL)
241
+ [ -n "$WPE_PROD" ] && VALUE="$WPE_PROD" || {
242
+ read -r -p " Production install slug (e.g. mysite): " VALUE
243
+ }
244
+ ;;
245
+
246
+ WPE_PROD_GIT_URL)
247
+ SLUG="${WPE_PROD:-}"
248
+ if [ -z "$SLUG" ]; then
249
+ # Try to get from wp-cli.yml
250
+ SLUG=$(grep -A2 '@production' wp-cli.yml 2>/dev/null | grep 'ssh:' | awk '{print $2}' | cut -d@ -f1 || echo "")
251
+ fi
252
+ info "Get exact URL from: https://my.wpengine.com/installs/${SLUG:-<install>}/git_push"
253
+ read -r -p " Production git URL (e.g. git@git.wpengine.com:mysite.git): " VALUE
254
+ ;;
255
+
256
+ WPE_STAGING_INSTALL)
257
+ [ -n "$WPE_STAGING" ] && VALUE="$WPE_STAGING" || {
258
+ read -r -p " Staging install slug (e.g. mysitestg): " VALUE
259
+ }
260
+ ;;
261
+
262
+ WPE_STAGING_GIT_URL)
263
+ SLUG="${WPE_STAGING:-}"
264
+ info "Get exact URL from: https://my.wpengine.com/installs/${SLUG:-<install>}/git_push"
265
+ read -r -p " Staging git URL (e.g. git@git.wpengine.com:mysitestg.git): " VALUE
266
+ ;;
267
+
268
+ WPE_DEV_INSTALL)
269
+ [ -n "$WPE_DEV" ] && VALUE="$WPE_DEV" || {
270
+ read -r -p " Dev install slug (e.g. mysitedev): " VALUE
271
+ }
272
+ ;;
273
+
274
+ WPE_DEV_GIT_URL)
275
+ SLUG="${WPE_DEV:-}"
276
+ info "Get exact URL from: https://my.wpengine.com/installs/${SLUG:-<install>}/git_push"
277
+ read -r -p " Dev git URL (e.g. git@git.wpengine.com:mysitedev.git): " VALUE
278
+ ;;
279
+
280
+ WPE_API_USER)
281
+ info "Find at: https://my.wpengine.com/api_access"
282
+ read -r -p " WP Engine API username: " VALUE
283
+ ;;
284
+
285
+ WPE_API_PASSWORD)
286
+ info "Find at: https://my.wpengine.com/api_access"
287
+ read -r -s -p " WP Engine API password (hidden): " VALUE
288
+ echo ""
289
+ ;;
290
+ esac
291
+
292
+ if [ -n "$VALUE" ]; then
293
+ echo "$VALUE" | gh secret set "$secret" --repo "${OWNER}/${REPO}"
294
+ ok "$secret set"
295
+ else
296
+ warn "$secret skipped"
297
+ fi
298
+ done
299
+ fi
300
+
301
+ # ── 6. Branch protection ──────────────────────────────────────────────────────
302
+ sep "Branch Protection"
303
+
304
+ check_branch_protection() {
305
+ local branch="$1"
306
+ local prot
307
+ prot=$(gh api "repos/${OWNER}/${REPO}/branches/${branch}/protection" 2>/dev/null || echo "")
308
+ if [ -z "$prot" ] || echo "$prot" | grep -q '"message"'; then
309
+ warn "${branch}: not protected"
310
+ return 1
311
+ fi
312
+ local checks
313
+ checks=$(echo "$prot" | python3 -c "
314
+ import sys,json
315
+ p = json.load(sys.stdin)
316
+ checks = p.get('required_status_checks',{}).get('contexts',[])
317
+ reviews = p.get('required_pull_request_reviews',{}).get('required_approving_review_count',0)
318
+ print(f'status checks={checks}, reviewers={reviews}')
319
+ " 2>/dev/null || echo "configured")
320
+ ok "${branch}: protected (${checks})"
321
+ return 0
322
+ }
323
+
324
+ BRANCHES_NEEDING_PROTECTION=()
325
+
326
+ for branch in "$DEFAULT_BRANCH" "staging" "develop"; do
327
+ if ! check_branch_protection "$branch" 2>/dev/null; then
328
+ BRANCHES_NEEDING_PROTECTION+=("$branch")
329
+ fi
330
+ done
331
+
332
+ if [ "${#BRANCHES_NEEDING_PROTECTION[@]}" -eq 0 ]; then
333
+ ok "Branch protection looks good"
334
+ elif ! $SET_PROTECTION; then
335
+ warn "${#BRANCHES_NEEDING_PROTECTION[@]} branch(es) not protected — run with --set-protection to configure"
336
+ fi
337
+
338
+ # ── 7. Apply branch protection ────────────────────────────────────────────────
339
+ if $SET_PROTECTION && [ "${#BRANCHES_NEEDING_PROTECTION[@]}" -gt 0 ]; then
340
+ sep "Configuring Branch Protection"
341
+
342
+ for branch in "${BRANCHES_NEEDING_PROTECTION[@]}"; do
343
+ echo ""
344
+ info "Configuring: ${branch}"
345
+
346
+ # Determine required reviewer count
347
+ if [ "$branch" = "$DEFAULT_BRANCH" ]; then
348
+ REVIEWERS=2 # Production needs 2
349
+ else
350
+ REVIEWERS=1 # Staging/develop needs 1
351
+ fi
352
+
353
+ # Required status checks — gate-passed is the canonical check from ci-gate.yml
354
+ CONTEXTS='["gate-passed"]'
355
+
356
+ # For production, also require staging-source-check
357
+ if [ "$branch" = "$DEFAULT_BRANCH" ]; then
358
+ CONTEXTS='["gate-passed","staging-source-check"]'
359
+ fi
360
+
361
+ if ! confirm " Set ${branch} protection (${REVIEWERS} reviewers, checks: ${CONTEXTS})?"; then
362
+ warn "${branch}: skipped"
363
+ continue
364
+ fi
365
+
366
+ PAYLOAD=$(python3 -c "
367
+ import json
368
+ contexts = ${CONTEXTS}
369
+ payload = {
370
+ 'required_status_checks': {
371
+ 'strict': True,
372
+ 'contexts': contexts
373
+ },
374
+ 'enforce_admins': True,
375
+ 'required_pull_request_reviews': {
376
+ 'dismiss_stale_reviews': True,
377
+ 'require_code_owner_reviews': False,
378
+ 'required_approving_review_count': ${REVIEWERS}
379
+ },
380
+ 'restrictions': None,
381
+ 'allow_force_pushes': False,
382
+ 'allow_deletions': False
383
+ }
384
+ print(json.dumps(payload))
385
+ ")
386
+
387
+ if echo "$PAYLOAD" | gh api "repos/${OWNER}/${REPO}/branches/${branch}/protection" \
388
+ --method PUT --input - >/dev/null 2>&1; then
389
+ ok "${branch}: protection configured (${REVIEWERS} reviewer(s), checks: ${CONTEXTS})"
390
+ else
391
+ fail "${branch}: failed to configure protection"
392
+ info "You may need admin access or a GitHub token with 'repo' scope"
393
+ fi
394
+ done
395
+ fi
396
+
397
+ # ── 8. Summary ────────────────────────────────────────────────────────────────
398
+ sep "Summary"
399
+
400
+ TOTAL_MISSING="${#MISSING_SECRETS[@]}"
401
+ TOTAL_UNPROTECTED="${#BRANCHES_NEEDING_PROTECTION[@]}"
402
+
403
+ if [ "$TOTAL_MISSING" -eq 0 ] && [ "$TOTAL_UNPROTECTED" -eq 0 ]; then
404
+ ok "GitHub repo is fully configured for WP Engine CI/CD"
405
+ ok "Secrets: all set | Branch protection: all configured"
406
+ else
407
+ [ "$TOTAL_MISSING" -gt 0 ] && warn "Secrets missing: $TOTAL_MISSING (run --set-secrets)"
408
+ [ "$TOTAL_UNPROTECTED" -gt 0 ] && warn "Branches unprotected: ${BRANCHES_NEEDING_PROTECTION[*]} (run --set-protection)"
409
+ echo ""
410
+ info "Re-run: bash ${0} --set-all"
411
+ fi
412
+
413
+ echo ""
414
+ info "GitHub Actions: https://github.com/${OWNER}/${REPO}/actions"
415
+ info "Secrets: https://github.com/${OWNER}/${REPO}/settings/secrets/actions"
416
+ info "Branch rules: https://github.com/${OWNER}/${REPO}/settings/branches"
417
+ echo ""
@@ -21,12 +21,14 @@ Use this skill when the task involves WordPress operational work via WP-CLI, inc
21
21
 
22
22
  ## Inputs required
23
23
 
24
- - Where WP-CLI will run (local dev, staging, production) and whether its safe to run.
24
+ - Where WP-CLI will run (local dev, staging, production) and whether it's safe to run.
25
25
  - How to target the correct site root:
26
26
  - `--path=<wordpress-root>` and (multisite) `--url=<site-url>`
27
27
  - Whether this is multisite and whether commands should run network-wide.
28
28
  - Any constraints (no downtime, no DB writes, maintenance window).
29
29
 
30
+ > **Running on WP Engine?** Use the `wp-wpengine` skill for SSH gateway setup, the `--ssh` flag, and `wp-cli.yml` remote aliases for WP Engine installs. Return here for the WP-CLI operation patterns themselves.
31
+
30
32
  ## Procedure
31
33
 
32
34
  ### 0) Guardrails: confirm environment and blast radius
@@ -34,7 +36,7 @@ Use this skill when the task involves WordPress operational work via WP-CLI, inc
34
36
  WP-CLI commands can be destructive. Before running anything that writes:
35
37
 
36
38
  1. Confirm environment (dev/staging/prod).
37
- 2. Confirm targeting (path/url) so you dont hit the wrong site.
39
+ 2. Confirm targeting (path/url) so you don't hit the wrong site.
38
40
  3. Make a backup when performing risky operations.
39
41
 
40
42
  Read:
@@ -46,7 +48,7 @@ Run the inspector:
46
48
 
47
49
  - `node skills/wp-wpcli-and-ops/scripts/wpcli_inspect.mjs --path=<path> [--url=<url>]`
48
50
 
49
- If WP-CLI isnt available, fall back to installing it via the projects documented tooling (Composer, container, or system package), or ask for the expected execution environment.
51
+ If WP-CLI isn't available, fall back to installing it via the project's documented tooling (Composer, container, or system package), or ask for the expected execution environment.
50
52
 
51
53
  ### 2) Choose the right workflow
52
54
 
@@ -64,21 +66,21 @@ Read:
64
66
 
65
67
  #### B) Plugin/theme operations
66
68
 
67
- Use `wp plugin *` / `wp theme *` and confirm youre acting on the intended site (and network) first.
69
+ Use `wp plugin *` / `wp theme *` and confirm you're acting on the intended site (and network) first.
68
70
 
69
71
  Read:
70
72
  - `references/packages-and-updates.md`
71
73
 
72
74
  #### C) Cron and queues
73
75
 
74
- Inspect cron state and run individual events for debugging rather than run everything blindly”.
76
+ Inspect cron state and run individual events for debugging rather than "run everything blindly".
75
77
 
76
78
  Read:
77
79
  - `references/cron-and-cache.md`
78
80
 
79
81
  #### D) Multisite operations
80
82
 
81
- Multisite changes can affect many sites. Always decide whether youre operating:
83
+ Multisite changes can affect many sites. Always decide whether you're operating:
82
84
 
83
85
  - on a single site (`--url=`), or
84
86
  - network-wide (`--network` / iterating sites)
@@ -104,11 +106,11 @@ Read:
104
106
  - correct URLs updated
105
107
  - plugins/themes in expected state
106
108
  - cron/caches flushed where needed
107
- - If theres a health check endpoint or smoke test suite, run it after ops changes.
109
+ - If there's a health check endpoint or smoke test suite, run it after ops changes.
108
110
 
109
111
  ## Failure modes / debugging
110
112
 
111
- - Error: This does not seem to be a WordPress installation.”
113
+ - "Error: This does not seem to be a WordPress installation."
112
114
  - wrong `--path`, wrong container, or missing `wp-config.php`
113
115
  - Multisite commands affecting the wrong site
114
116
  - missing `--url` or wrong URL
@@ -121,4 +123,4 @@ See:
121
123
  ## Escalation
122
124
 
123
125
  - If you cannot confirm environment safety, do not run write operations.
124
- - If the repo uses containerized tooling (Docker/wp-env) but you cant access it, ask for the intended command runner or CI job.
126
+ - If the repo uses containerized tooling (Docker/wp-env) but you can't access it, ask for the intended command runner or CI job.