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.
- package/.agents/skills/wp-bootstrap/SKILL.md +314 -0
- package/.agents/skills/wp-bootstrap/references/composer-setup.md +275 -0
- package/.agents/skills/wp-bootstrap/references/monorepo-patterns.md +184 -0
- package/.agents/skills/wp-bootstrap/scripts/bootstrap.sh +151 -0
- package/.agents/skills/wp-bootstrap/scripts/detect-structure.mjs +466 -0
- package/.agents/skills/wp-bootstrap/scripts/package-wp.sh +173 -0
- package/.agents/skills/wp-bootstrap/scripts/playground-start.sh +148 -0
- package/.agents/skills/wp-bootstrap/scripts/playground-verify.sh +165 -0
- package/.agents/skills/wp-bootstrap/scripts/setup-github.sh +417 -0
- package/{.github → .agents}/skills/wp-wpcli-and-ops/SKILL.md +11 -9
- package/.agents/skills/wp-wpengine/SKILL.md +462 -0
- package/.agents/skills/wp-wpengine/references/ci-gate.md +469 -0
- package/.agents/skills/wp-wpengine/references/github-actions-deploy.md +743 -0
- package/.agents/skills/wp-wpengine/scripts/ci-gate.sh +118 -0
- package/.agents/skills/wp-wpengine/scripts/wpe-check.sh +89 -0
- package/.agents/skills/wp-wpengine/scripts/wpe-preflight.sh +104 -0
- package/.github/agents/wp-architect.agent.md +1 -2
- package/.github/copilot-instructions.md +1 -1
- package/.github/instructions/wordpress-workflow.instructions.md +3 -3
- package/AGENTS.md +22 -10
- package/AGENTS.template.md +20 -10
- package/README.md +89 -85
- package/dist/cli.js +7 -1
- package/dist/commands/bootstrap.js +105 -0
- package/dist/commands/clean-skills.js +64 -0
- package/dist/commands/setup.js +6 -2
- package/dist/commands/sync-skills.js +3 -0
- package/dist/lib/api.js +165 -5
- package/dist/lib/bootstrap.js +352 -0
- package/dist/lib/installer.js +166 -2
- package/extensions/wp-agent-kit/index.ts +325 -10
- package/package.json +10 -14
- package/skills-custom/wp-bootstrap/SKILL.md +314 -0
- package/skills-custom/wp-bootstrap/references/composer-setup.md +275 -0
- package/skills-custom/wp-bootstrap/references/monorepo-patterns.md +184 -0
- package/skills-custom/wp-bootstrap/scripts/bootstrap.sh +151 -0
- package/skills-custom/wp-bootstrap/scripts/detect-structure.mjs +466 -0
- package/skills-custom/wp-bootstrap/scripts/package-wp.sh +173 -0
- package/skills-custom/wp-bootstrap/scripts/playground-start.sh +148 -0
- package/skills-custom/wp-bootstrap/scripts/playground-verify.sh +165 -0
- package/skills-custom/wp-bootstrap/scripts/setup-github.sh +417 -0
- package/skills-custom/wp-wpengine/SKILL.md +362 -27
- package/skills-custom/wp-wpengine/references/ci-gate.md +469 -0
- package/skills-custom/wp-wpengine/references/github-actions-deploy.md +743 -0
- package/skills-custom/wp-wpengine/scripts/ci-gate.sh +118 -0
- package/skills-custom/wp-wpengine/scripts/wpe-check.sh +89 -0
- package/skills-custom/wp-wpengine/scripts/wpe-preflight.sh +104 -0
- package/.github/skills/wp-wpengine/SKILL.md +0 -127
- package/.github/workflows/ci.yml +0 -44
- package/.husky/pre-commit +0 -7
- package/CLI_REVIEW.md +0 -250
- package/biome.json +0 -39
- /package/{.github → .agents}/skills/blueprint/SKILL.md +0 -0
- /package/{.github → .agents}/skills/wordpress-router/SKILL.md +0 -0
- /package/{.github → .agents}/skills/wordpress-router/references/decision-tree.md +0 -0
- /package/{.github → .agents}/skills/wp-abilities-api/SKILL.md +0 -0
- /package/{.github → .agents}/skills/wp-abilities-api/references/delegate-helper-pattern.md +0 -0
- /package/{.github → .agents}/skills/wp-abilities-api/references/domain-vs-projection.md +0 -0
- /package/{.github → .agents}/skills/wp-abilities-api/references/error-code-vocabulary.md +0 -0
- /package/{.github → .agents}/skills/wp-abilities-api/references/grouping-heuristic.md +0 -0
- /package/{.github → .agents}/skills/wp-abilities-api/references/input-schema-gotchas.md +0 -0
- /package/{.github → .agents}/skills/wp-abilities-api/references/php-registration.md +0 -0
- /package/{.github → .agents}/skills/wp-abilities-api/references/plugin-family-patterns.md +0 -0
- /package/{.github → .agents}/skills/wp-abilities-api/references/rest-api.md +0 -0
- /package/{.github → .agents}/skills/wp-abilities-api/references/shared-core-service.md +0 -0
- /package/{.github → .agents}/skills/wp-abilities-audit/SKILL.md +0 -0
- /package/{.github → .agents}/skills/wp-abilities-audit/references/audit-schema.md +0 -0
- /package/{.github → .agents}/skills/wp-abilities-audit/references/capability-gate-tracing.md +0 -0
- /package/{.github → .agents}/skills/wp-abilities-audit/references/controller-enumeration.md +0 -0
- /package/{.github → .agents}/skills/wp-abilities-verify/SKILL.md +0 -0
- /package/{.github → .agents}/skills/wp-abilities-verify/references/annotation-correctness.md +0 -0
- /package/{.github → .agents}/skills/wp-abilities-verify/references/audit-schema-validation.md +0 -0
- /package/{.github → .agents}/skills/wp-abilities-verify/references/permission-roundtrip.md +0 -0
- /package/{.github → .agents}/skills/wp-abilities-verify/references/runtime-harness.md +0 -0
- /package/{.github → .agents}/skills/wp-abilities-verify/references/schema-lints.md +0 -0
- /package/{.github → .agents}/skills/wp-abilities-verify/references/static-enumeration.md +0 -0
- /package/{.github → .agents}/skills/wp-block-development/SKILL.md +0 -0
- /package/{.github → .agents}/skills/wp-block-development/references/attributes-and-serialization.md +0 -0
- /package/{.github → .agents}/skills/wp-block-development/references/block-json.md +0 -0
- /package/{.github → .agents}/skills/wp-block-development/references/creating-new-blocks.md +0 -0
- /package/{.github → .agents}/skills/wp-block-development/references/debugging.md +0 -0
- /package/{.github → .agents}/skills/wp-block-development/references/deprecations.md +0 -0
- /package/{.github → .agents}/skills/wp-block-development/references/dynamic-rendering.md +0 -0
- /package/{.github → .agents}/skills/wp-block-development/references/inner-blocks.md +0 -0
- /package/{.github → .agents}/skills/wp-block-development/references/registration.md +0 -0
- /package/{.github → .agents}/skills/wp-block-development/references/supports-and-wrappers.md +0 -0
- /package/{.github → .agents}/skills/wp-block-development/references/tooling-and-testing.md +0 -0
- /package/{.github → .agents}/skills/wp-block-development/scripts/list_blocks.mjs +0 -0
- /package/{.github → .agents}/skills/wp-block-themes/SKILL.md +0 -0
- /package/{.github → .agents}/skills/wp-block-themes/references/creating-new-block-theme.md +0 -0
- /package/{.github → .agents}/skills/wp-block-themes/references/debugging.md +0 -0
- /package/{.github → .agents}/skills/wp-block-themes/references/patterns.md +0 -0
- /package/{.github → .agents}/skills/wp-block-themes/references/style-variations.md +0 -0
- /package/{.github → .agents}/skills/wp-block-themes/references/templates-and-parts.md +0 -0
- /package/{.github → .agents}/skills/wp-block-themes/references/theme-json.md +0 -0
- /package/{.github → .agents}/skills/wp-block-themes/scripts/detect_block_themes.mjs +0 -0
- /package/{.github → .agents}/skills/wp-interactivity-api/SKILL.md +0 -0
- /package/{.github → .agents}/skills/wp-interactivity-api/references/debugging.md +0 -0
- /package/{.github → .agents}/skills/wp-interactivity-api/references/directives-quickref.md +0 -0
- /package/{.github → .agents}/skills/wp-interactivity-api/references/server-side-rendering.md +0 -0
- /package/{.github → .agents}/skills/wp-performance/SKILL.md +0 -0
- /package/{.github → .agents}/skills/wp-performance/references/autoload-options.md +0 -0
- /package/{.github → .agents}/skills/wp-performance/references/cron.md +0 -0
- /package/{.github → .agents}/skills/wp-performance/references/database.md +0 -0
- /package/{.github → .agents}/skills/wp-performance/references/http-api.md +0 -0
- /package/{.github → .agents}/skills/wp-performance/references/measurement.md +0 -0
- /package/{.github → .agents}/skills/wp-performance/references/object-cache.md +0 -0
- /package/{.github → .agents}/skills/wp-performance/references/query-monitor-headless.md +0 -0
- /package/{.github → .agents}/skills/wp-performance/references/server-timing.md +0 -0
- /package/{.github → .agents}/skills/wp-performance/references/wp-cli-doctor.md +0 -0
- /package/{.github → .agents}/skills/wp-performance/references/wp-cli-profile.md +0 -0
- /package/{.github → .agents}/skills/wp-performance/scripts/perf_inspect.mjs +0 -0
- /package/{.github → .agents}/skills/wp-phpstan/SKILL.md +0 -0
- /package/{.github → .agents}/skills/wp-phpstan/references/configuration.md +0 -0
- /package/{.github → .agents}/skills/wp-phpstan/references/third-party-classes.md +0 -0
- /package/{.github → .agents}/skills/wp-phpstan/references/wordpress-annotations.md +0 -0
- /package/{.github → .agents}/skills/wp-phpstan/scripts/phpstan_inspect.mjs +0 -0
- /package/{.github → .agents}/skills/wp-playground/SKILL.md +0 -0
- /package/{.github → .agents}/skills/wp-playground/references/blueprints.md +0 -0
- /package/{.github → .agents}/skills/wp-playground/references/cli-commands.md +0 -0
- /package/{.github → .agents}/skills/wp-playground/references/debugging.md +0 -0
- /package/{.github → .agents}/skills/wp-playground/references/e2e-playwright.md +0 -0
- /package/{.github → .agents}/skills/wp-plugin-development/SKILL.md +0 -0
- /package/{.github → .agents}/skills/wp-plugin-development/references/data-and-cron.md +0 -0
- /package/{.github → .agents}/skills/wp-plugin-development/references/debugging.md +0 -0
- /package/{.github → .agents}/skills/wp-plugin-development/references/lifecycle.md +0 -0
- /package/{.github → .agents}/skills/wp-plugin-development/references/security.md +0 -0
- /package/{.github → .agents}/skills/wp-plugin-development/references/settings-api.md +0 -0
- /package/{.github → .agents}/skills/wp-plugin-development/references/structure.md +0 -0
- /package/{.github → .agents}/skills/wp-plugin-development/scripts/detect_plugins.mjs +0 -0
- /package/{.github → .agents}/skills/wp-plugin-directory-guidelines/SKILL.md +0 -0
- /package/{.github → .agents}/skills/wp-plugin-directory-guidelines/references/gpl-compliance.md +0 -0
- /package/{.github → .agents}/skills/wp-plugin-directory-guidelines/references/guideline-review-checklist.md +0 -0
- /package/{.github → .agents}/skills/wp-plugin-directory-guidelines/references/naming-rules.md +0 -0
- /package/{.github → .agents}/skills/wp-project-triage/SKILL.md +0 -0
- /package/{.github → .agents}/skills/wp-project-triage/references/triage.schema.json +0 -0
- /package/{.github → .agents}/skills/wp-project-triage/scripts/detect_wp_project.mjs +0 -0
- /package/{.github → .agents}/skills/wp-rest-api/SKILL.md +0 -0
- /package/{.github → .agents}/skills/wp-rest-api/references/authentication.md +0 -0
- /package/{.github → .agents}/skills/wp-rest-api/references/custom-content-types.md +0 -0
- /package/{.github → .agents}/skills/wp-rest-api/references/discovery-and-params.md +0 -0
- /package/{.github → .agents}/skills/wp-rest-api/references/responses-and-fields.md +0 -0
- /package/{.github → .agents}/skills/wp-rest-api/references/routes-and-endpoints.md +0 -0
- /package/{.github → .agents}/skills/wp-rest-api/references/schema.md +0 -0
- /package/{.github → .agents}/skills/wp-wpcli-and-ops/references/automation.md +0 -0
- /package/{.github → .agents}/skills/wp-wpcli-and-ops/references/cron-and-cache.md +0 -0
- /package/{.github → .agents}/skills/wp-wpcli-and-ops/references/debugging.md +0 -0
- /package/{.github → .agents}/skills/wp-wpcli-and-ops/references/multisite.md +0 -0
- /package/{.github → .agents}/skills/wp-wpcli-and-ops/references/packages-and-updates.md +0 -0
- /package/{.github → .agents}/skills/wp-wpcli-and-ops/references/safety.md +0 -0
- /package/{.github → .agents}/skills/wp-wpcli-and-ops/references/search-replace.md +0 -0
- /package/{.github → .agents}/skills/wp-wpcli-and-ops/scripts/wpcli_inspect.mjs +0 -0
- /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 it
|
|
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 don
|
|
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 isn
|
|
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 you
|
|
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
|
|
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 you
|
|
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 there
|
|
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
|
-
-
|
|
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 can
|
|
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.
|