wordpress-agent-kit 0.3.0 → 0.4.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/.github/skills/blueprint/SKILL.md +418 -0
- package/.github/skills/wp-abilities-api/SKILL.md +12 -0
- package/.github/skills/wp-abilities-api/references/delegate-helper-pattern.md +241 -0
- package/.github/skills/wp-abilities-api/references/domain-vs-projection.md +113 -0
- package/.github/skills/wp-abilities-api/references/error-code-vocabulary.md +123 -0
- package/.github/skills/wp-abilities-api/references/grouping-heuristic.md +89 -0
- package/.github/skills/wp-abilities-api/references/input-schema-gotchas.md +265 -0
- package/.github/skills/wp-abilities-api/references/php-registration.md +47 -20
- package/.github/skills/wp-abilities-api/references/plugin-family-patterns.md +233 -0
- package/.github/skills/wp-abilities-api/references/shared-core-service.md +184 -0
- package/.github/skills/wp-abilities-audit/SKILL.md +199 -0
- package/.github/skills/wp-abilities-audit/references/audit-schema.md +300 -0
- package/.github/skills/wp-abilities-audit/references/capability-gate-tracing.md +197 -0
- package/.github/skills/wp-abilities-audit/references/controller-enumeration.md +116 -0
- package/.github/skills/wp-abilities-verify/SKILL.md +215 -0
- package/.github/skills/wp-abilities-verify/references/annotation-correctness.md +154 -0
- package/.github/skills/wp-abilities-verify/references/audit-schema-validation.md +131 -0
- package/.github/skills/wp-abilities-verify/references/permission-roundtrip.md +190 -0
- package/.github/skills/wp-abilities-verify/references/runtime-harness.md +462 -0
- package/.github/skills/wp-abilities-verify/references/schema-lints.md +118 -0
- package/.github/skills/wp-abilities-verify/references/static-enumeration.md +126 -0
- package/.github/skills/wp-playground/SKILL.md +132 -1
- package/.github/skills/wp-playground/references/e2e-playwright.md +115 -0
- package/.github/skills/wp-plugin-directory-guidelines/SKILL.md +133 -0
- package/.github/skills/wp-plugin-directory-guidelines/references/gpl-compliance.md +217 -0
- package/.github/skills/wp-plugin-directory-guidelines/references/guideline-review-checklist.md +592 -0
- package/.github/skills/wp-plugin-directory-guidelines/references/naming-rules.md +121 -0
- package/.github/skills/wp-project-triage/scripts/detect_wp_project.mjs +22 -4
- package/.github/skills/wp-wpengine/SKILL.md +127 -0
- package/README.md +14 -8
- package/dist/lib/api.js +43 -19
- package/dist/lib/installer.js +0 -2
- package/extensions/wp-agent-kit/index.ts +146 -324
- package/package.json +1 -1
- package/skills-custom/wp-wpengine/SKILL.md +127 -0
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
## Plugin Naming Rules (Guideline 17 + Plugin Check Namer)
|
|
2
|
+
|
|
3
|
+
Sources: [Plugin Header Requirements](https://developer.wordpress.org/plugins/plugin-basics/header-requirements/#header-fields) · [Detailed Plugin Guidelines §17](https://developer.wordpress.org/plugins/wordpress-org/detailed-plugin-guidelines/) · Plugin Check `Plugin_Header_Fields_Check`, `Trademarks_Check`, and AI Namer prompts.
|
|
4
|
+
|
|
5
|
+
### Technical Name Requirements
|
|
6
|
+
|
|
7
|
+
| Rule | Details | Error Code |
|
|
8
|
+
|------|---------|------------|
|
|
9
|
+
| Must not use placeholder names | `"Plugin Name"` or `"My Basics Plugin"` are rejected | `plugin_header_invalid_plugin_name` |
|
|
10
|
+
| Minimum 5 alphanumeric characters | Name must contain at least 5 latin letters (a–Z) or digits | `plugin_header_unsupported_plugin_name` (new plugins only) |
|
|
11
|
+
| Name must exist in readme | `=== Plugin Name ===` header required and must be valid | `invalid_plugin_name` / `empty_plugin_name` |
|
|
12
|
+
| Name must match across files | Readme and plugin header name must match (case/entity-decoded) | `mismatched_plugin_name` (warning) |
|
|
13
|
+
|
|
14
|
+
**Slug rules:** lowercase, hyphens only, max 50 characters, derived from display name.
|
|
15
|
+
|
|
16
|
+
### Naming Quality Rules (AI Namer)
|
|
17
|
+
|
|
18
|
+
**1. No generic names**
|
|
19
|
+
Names must be specific enough to distinguish the plugin from ~60,000 others.
|
|
20
|
+
- Rejected: "Shipping", "Ecommerce Tracker", "SEO Plugin"
|
|
21
|
+
- Accepted: "ShipGlex Shipping", "Shipping Tracker for UPS"
|
|
22
|
+
- Exception: invented/original terms are allowed if placed at the **beginning** of the name
|
|
23
|
+
|
|
24
|
+
**2. Name must relate to plugin function**
|
|
25
|
+
The display name must correlate with what the plugin actually does. Exception: original invented terms.
|
|
26
|
+
|
|
27
|
+
**3. No keyword stuffing**
|
|
28
|
+
Unnaturally repeating keywords in the name for SEO purposes is not allowed.
|
|
29
|
+
|
|
30
|
+
**4. No names too similar to existing plugins**
|
|
31
|
+
Checked against the WordPress.org Plugin Directory. If similar, suggest a distinctive term (author name, brand, or crafted term) at the beginning.
|
|
32
|
+
|
|
33
|
+
**5. Trademark/project name usage rules**
|
|
34
|
+
Trademarks and project names are allowed **only** after connectors like `for`, `with`, `using`, or `and`:
|
|
35
|
+
- ✅ `"My Plugin for WooCommerce"` — trademark after "for", no affiliation implied
|
|
36
|
+
- ✅ `"Pricing Rates for WooCommerce"` — OK
|
|
37
|
+
- ❌ `"WooCommerce Pricing Rates"` — starts with trademark, implies affiliation
|
|
38
|
+
- ❌ `"Nicedev Paypal for WooCommerce"` — PayPal is not after a no-affiliation structure; correct form: `"Nicedev Payment Gateway with PayPal for WooCommerce"`
|
|
39
|
+
- ❌ `"PricingPress"` — portmanteau using `-Press` (WordPress trademark)
|
|
40
|
+
- Check for portmanteaus: names blending a trademark (e.g., `-Press`, `Woo-`) are not allowed
|
|
41
|
+
|
|
42
|
+
**6. Banned and discouraged terms**
|
|
43
|
+
|
|
44
|
+
Banned/discouraged terms cannot appear **anywhere** in the name — not even after `for`/`with`.
|
|
45
|
+
|
|
46
|
+
#### Banned Terms (hard block)
|
|
47
|
+
|
|
48
|
+
| Term | Reason |
|
|
49
|
+
|------|--------|
|
|
50
|
+
| Facebook, FB, fbook, Whatsapp, WA, Instagram, Insta, Gram, INS, Threads, Oculus | Meta legal request: no use in name, slug, or banners |
|
|
51
|
+
| WordPress, wordpess, wpress | WordPress trademark; redundant in the WP.org directory |
|
|
52
|
+
| WP (as standalone/redundant, e.g., "for WP") | Same as WordPress — redundant in context |
|
|
53
|
+
| Trustpilot | Direct request from trademark holder |
|
|
54
|
+
| Binance Pay | Direct request from trademark holder |
|
|
55
|
+
|
|
56
|
+
#### Discouraged Terms (must be removed)
|
|
57
|
+
|
|
58
|
+
| Term | Reason |
|
|
59
|
+
|------|--------|
|
|
60
|
+
| plugin (when redundant, e.g., "SEO Plugin") | Redundant; forbidden as first word |
|
|
61
|
+
| best, #1, First, Perfect, The most | Superlatives / unverifiable comparative claims |
|
|
62
|
+
| free (when redundant, e.g., "(free)") | All directory plugins are free — redundant |
|
|
63
|
+
| WP, W P (at beginning or end, referring to WordPress) | WordPress abbreviation — redundant |
|
|
64
|
+
| Gutenberg, gberg, guten, berg | Creates confusion; block editor is the current name |
|
|
65
|
+
|
|
66
|
+
### Trademark Slug List (static check — `Trademarks_Check`)
|
|
67
|
+
|
|
68
|
+
The following slugs are statically blocked. Terms ending in `-` cannot **begin** a slug; terms without `-` cannot appear **anywhere** in the slug. `woocommerce` (no dash) is allowed only as `for-woocommerce`, `with-woocommerce`, `using-woocommerce`, or `and-woocommerce`.
|
|
69
|
+
|
|
70
|
+
```
|
|
71
|
+
adobe-, adsense-, advanced-custom-fields-, adwords-, akismet-,
|
|
72
|
+
all-in-one-wp-migration, amazon-, android-, apple-, applenews-, applepay-,
|
|
73
|
+
aws-, azon-, bbpress-, bing-, booking-com, bootstrap-, buddypress-,
|
|
74
|
+
chatgpt-, chat-gpt-, cloudflare-, contact-form-7-, cpanel-, disqus-, divi-,
|
|
75
|
+
dropbox-, easy-digital-downloads-, elementor-, envato-,
|
|
76
|
+
fbook, facebook, fb-, fb-messenger, fedex-, feedburner, firefox-,
|
|
77
|
+
fontawesome-, font-awesome-, ganalytics-, gberg, github-, givewp-, google-,
|
|
78
|
+
googlebot-, googles-, gravity-form-, gravity-forms-, gravityforms-, gtmetrix-,
|
|
79
|
+
gutenberg, guten-, hubspot-, ig-, insta-, instagram, internet-explorer-,
|
|
80
|
+
ios-, jetpack-, macintosh-, macos-, mailchimp-, microsoft-,
|
|
81
|
+
ninja-forms-, oculus, onlyfans-, only-fans-, opera-, paddle-, paypal-,
|
|
82
|
+
pinterest-, plugin, skype-, stripe-, tiktok-, tik-tok-, trustpilot,
|
|
83
|
+
twitch-, twitter-, tweet, ups-, usps-, vvhatsapp, vvcommerce, vva-, vvoo,
|
|
84
|
+
wa-, webpush-vn, wh4tsapps, whatsapp, whats-app, watson, windows-,
|
|
85
|
+
wocommerce, woocom-, woocommerce, woocomerce, woo-commerce, woo-, wo-,
|
|
86
|
+
wordpress, wordpess, wpress, wp, wc, wp-mail-smtp-, yandex-, yahoo-,
|
|
87
|
+
yoast, youtube-, you-tube-
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
**Portmanteaus also blocked:** any slug starting with `woo` (case-insensitive) — e.g., `woopress`, `wooland`.
|
|
91
|
+
|
|
92
|
+
### Naming Examples
|
|
93
|
+
|
|
94
|
+
| Plugin Name | Verdict | Reason |
|
|
95
|
+
|-------------|---------|--------|
|
|
96
|
+
| `Shipping` | ❌ | Too generic |
|
|
97
|
+
| `Ecommerce Tracker` | ❌ | Too generic, no context |
|
|
98
|
+
| `Shipping Tracker for UPS` | ✅ | Descriptive + context |
|
|
99
|
+
| `ShipGlex Shipping` | ✅ | Invented term at beginning |
|
|
100
|
+
| `WooCommerce Pricing Rates` | ❌ | Starts with trademark |
|
|
101
|
+
| `Pricing Rates for WooCommerce` | ✅ | Trademark after "for" |
|
|
102
|
+
| `PricingPress` | ❌ | `-Press` portmanteau |
|
|
103
|
+
| `PRT Text editor for WP` | ❌ | WP is banned/redundant; correct: `PRT Text editor` |
|
|
104
|
+
| `Nicedev Paypal for WooCommerce` | ❌ | PayPal not after no-affiliation structure |
|
|
105
|
+
| `Nicedev Payment Gateway with PayPal for WooCommerce` | ✅ | Correct structure |
|
|
106
|
+
| `Best SEO Plugin for WordPress` | ❌ | Superlative + banned terms |
|
|
107
|
+
| `My Free Slider` | ❌ | "free" is redundant/discouraged |
|
|
108
|
+
|
|
109
|
+
### Naming Review Checklist (pre-submission)
|
|
110
|
+
|
|
111
|
+
- [ ] Name is not a placeholder (`Plugin Name`, `My Basics Plugin`)
|
|
112
|
+
- [ ] Name has at least 5 alphanumeric characters
|
|
113
|
+
- [ ] Name matches between plugin header and readme
|
|
114
|
+
- [ ] Name is specific — not too generic for 60,000+ plugins
|
|
115
|
+
- [ ] Name relates to what the plugin actually does
|
|
116
|
+
- [ ] No keyword stuffing
|
|
117
|
+
- [ ] No banned terms anywhere (Meta brands, WordPress/WP redundant, Trustpilot, Binance Pay)
|
|
118
|
+
- [ ] No discouraged terms (Plugin, Best/#1, Free, Gutenberg, standalone WP)
|
|
119
|
+
- [ ] Trademarks/project names only appear after `for`/`with`/`using`/`and`
|
|
120
|
+
- [ ] No portmanteaus using WordPress or WooCommerce trademarks
|
|
121
|
+
- [ ] Slug is lowercase, hyphens only, max 50 chars, no blocked terms
|
|
@@ -124,7 +124,8 @@ function findFilesRecursive(repoRoot, predicate, { maxFiles = 6000, maxDepth = 8
|
|
|
124
124
|
function detectPluginHeaderFromPhpFile(filePath) {
|
|
125
125
|
const contents = readFileSafe(filePath, 128 * 1024);
|
|
126
126
|
if (!contents) return null;
|
|
127
|
-
|
|
127
|
+
// Allow leading whitespace and asterisks common in block comments
|
|
128
|
+
const headerMatch = contents.match(/^[ \\t*]*Plugin Name:\s*(.+)\s*$/im);
|
|
128
129
|
if (!headerMatch) return null;
|
|
129
130
|
return headerMatch[1].trim();
|
|
130
131
|
}
|
|
@@ -132,7 +133,8 @@ function detectPluginHeaderFromPhpFile(filePath) {
|
|
|
132
133
|
function detectThemeHeaderFromStyleCss(filePath) {
|
|
133
134
|
const contents = readFileSafe(filePath, 128 * 1024);
|
|
134
135
|
if (!contents) return null;
|
|
135
|
-
|
|
136
|
+
// Allow leading whitespace and asterisks common in block comments
|
|
137
|
+
const headerMatch = contents.match(/^[ \\t*]*Theme Name:\s*(.+)\s*$/im);
|
|
136
138
|
if (!headerMatch) return null;
|
|
137
139
|
return headerMatch[1].trim();
|
|
138
140
|
}
|
|
@@ -397,6 +399,13 @@ function main() {
|
|
|
397
399
|
maxDepth: 8,
|
|
398
400
|
});
|
|
399
401
|
|
|
402
|
+
const restApiScan = scanForTokens(repoRoot, {
|
|
403
|
+
tokens: ["register_rest_route", "register_rest_field", "WP_REST_Controller"],
|
|
404
|
+
exts: [".php"],
|
|
405
|
+
maxFiles: 2500,
|
|
406
|
+
maxDepth: 8,
|
|
407
|
+
});
|
|
408
|
+
|
|
400
409
|
const wpCliConfigBasenames = new Set([
|
|
401
410
|
"wp-cli.yml",
|
|
402
411
|
"wp-cli.yaml",
|
|
@@ -439,6 +448,7 @@ function main() {
|
|
|
439
448
|
|
|
440
449
|
const usesInteractivityApi = pkgHasInteractivity || Object.keys(interactivityScan.matches).length > 0;
|
|
441
450
|
const usesAbilitiesApi = pkgHasAbilities || Object.keys(abilitiesScan.matches).length > 0;
|
|
451
|
+
const usesRestApi = Object.keys(restApiScan.matches).length > 0;
|
|
442
452
|
const usesInnerBlocks = Object.keys(innerBlocksScan.matches).length > 0;
|
|
443
453
|
const usesWpCli = composerHasWpCli || wpCliConfigFiles.length > 0 || Object.keys(wpCliTokenScan.matches).length > 0;
|
|
444
454
|
|
|
@@ -476,6 +486,10 @@ function main() {
|
|
|
476
486
|
);
|
|
477
487
|
|
|
478
488
|
const hasPhpUnit = phpunitXml.length > 0 || Boolean(composerJson?.requireDev?.phpunit || composerJson?.["require-dev"]?.phpunit);
|
|
489
|
+
|
|
490
|
+
const hasPhpStan = existsFile(path.join(repoRoot, "phpstan.neon")) ||
|
|
491
|
+
existsFile(path.join(repoRoot, "phpstan.neon.dist")) ||
|
|
492
|
+
Boolean(composerJson?.requireDev?.["phpstan/phpstan"] || composerJson?.["require-dev"]?.["phpstan/phpstan"]);
|
|
479
493
|
|
|
480
494
|
const signals = {
|
|
481
495
|
paths: {
|
|
@@ -496,8 +510,7 @@ function main() {
|
|
|
496
510
|
isBlockPlugin,
|
|
497
511
|
isBlockTheme,
|
|
498
512
|
usesInteractivityApi,
|
|
499
|
-
usesAbilitiesApi,
|
|
500
|
-
usesInnerBlocks,
|
|
513
|
+
usesAbilitiesApi, usesRestApi, usesInnerBlocks,
|
|
501
514
|
usesWpCli,
|
|
502
515
|
performanceHints: {
|
|
503
516
|
wpConfig: config.source,
|
|
@@ -523,6 +536,10 @@ function main() {
|
|
|
523
536
|
matches: abilitiesScan.matches,
|
|
524
537
|
scanTruncated: abilitiesScan.truncated,
|
|
525
538
|
},
|
|
539
|
+
restApiHints: {
|
|
540
|
+
matches: restApiScan.matches,
|
|
541
|
+
scanTruncated: restApiScan.truncated,
|
|
542
|
+
},
|
|
526
543
|
innerBlocksHints: {
|
|
527
544
|
matches: innerBlocksScan.matches,
|
|
528
545
|
scanTruncated: innerBlocksScan.truncated,
|
|
@@ -552,6 +569,7 @@ function main() {
|
|
|
552
569
|
php: {
|
|
553
570
|
hasComposerJson: existsFile(path.join(repoRoot, "composer.json")),
|
|
554
571
|
hasVendorDir: existsDir(path.join(repoRoot, "vendor")),
|
|
572
|
+
hasPhpStan,
|
|
555
573
|
phpunitXml,
|
|
556
574
|
},
|
|
557
575
|
node: {
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: wp-wpengine
|
|
3
|
+
description: "Optional: Use for WP Engine hosting workflows — SSH-based git push to WP Engine environments, managing installs/domains/cache/backups via the wpe-labs Claude Code skills, and WP Engine API access. Requires WPE_USERNAME and WPE_PASSWORD env vars."
|
|
4
|
+
license: GPL-2.0-or-later
|
|
5
|
+
optional: true
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# WP Engine
|
|
9
|
+
|
|
10
|
+
## When to use
|
|
11
|
+
|
|
12
|
+
- Deploy WordPress code to a WP Engine environment via `git push`.
|
|
13
|
+
- Manage WP Engine installs, domains, cache, backups, or users through natural language.
|
|
14
|
+
- Generate monthly usage/bandwidth reports across WP Engine accounts.
|
|
15
|
+
- Manage LargeFS media offload configuration.
|
|
16
|
+
|
|
17
|
+
## Prerequisites
|
|
18
|
+
|
|
19
|
+
- SSH key for WP Engine git push stored in 1Password (`Employee` vault, item `wpengine_ed25519`).
|
|
20
|
+
- WP Engine API credentials in 1Password (`Employee` vault, item `WP Engine API`).
|
|
21
|
+
- `op` CLI authenticated (`op whoami` works).
|
|
22
|
+
- The `wpe-labs` Claude Code skills installed (`~/.claude/skills/wpe-labs:*`).
|
|
23
|
+
|
|
24
|
+
## Procedure
|
|
25
|
+
|
|
26
|
+
### 1) First-time SSH setup on a new machine
|
|
27
|
+
|
|
28
|
+
Pull the private key from 1Password and configure SSH:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
op read "op://Employee/wpengine_ed25519/private key" > ~/.ssh/wpengine_ed25519
|
|
32
|
+
chmod 600 ~/.ssh/wpengine_ed25519
|
|
33
|
+
ssh-keyscan git.wpengine.com >> ~/.ssh/known_hosts
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Add to `~/.ssh/config` (before any `Host *` block):
|
|
37
|
+
```
|
|
38
|
+
Host git.wpengine.com
|
|
39
|
+
User git
|
|
40
|
+
IdentityFile ~/.ssh/wpengine_ed25519
|
|
41
|
+
IdentitiesOnly yes
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Verify:
|
|
45
|
+
```bash
|
|
46
|
+
ssh git@git.wpengine.com info
|
|
47
|
+
# Expected: hello <username> / R W <install-name>
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
The public key is already registered on WP Engine — no portal action needed on new machines.
|
|
51
|
+
|
|
52
|
+
### 2) Add a WP Engine git remote
|
|
53
|
+
|
|
54
|
+
Find the remote URL on the WP Engine portal: `https://my.wpengine.com/installs/<ENV>/git_push`
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
git remote add wpengine git@git.wpengine.com:<install-name>.git
|
|
58
|
+
# Example for staging:
|
|
59
|
+
git remote add wpengine-staging git@git.wpengine.com:<install-name>stg.git
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### 3) Deploy via git push
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
git push wpengine main
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
- WP Engine deploys the pushed branch automatically.
|
|
69
|
+
- Only the WordPress files are pushed (not `node_modules`, build artifacts, etc.).
|
|
70
|
+
- After push, WP Engine may take 1–2 min to propagate the deploy.
|
|
71
|
+
|
|
72
|
+
### 4) wpe-labs skills (natural language management)
|
|
73
|
+
|
|
74
|
+
Load API credentials, then use any `/wpe-labs:*` skill:
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
# Load credentials from 1Password for the session
|
|
78
|
+
eval $(op run --env-file ~/.config/op-ssh/.env.1pass -- env | grep ^WPE | sed 's/^/export /')
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Available skills:
|
|
82
|
+
|
|
83
|
+
| Skill | What it does | Risk |
|
|
84
|
+
|---|---|---|
|
|
85
|
+
| `/wpe-labs:account-usage` | Bandwidth, visits, storage across accounts | 🟢 Read-only |
|
|
86
|
+
| `/wpe-labs:monthly-report` | Client-ready monthly usage report | 🟢 Read-only |
|
|
87
|
+
| `/wpe-labs:backups` | On-demand backups + progress monitoring | 🟡 Write |
|
|
88
|
+
| `/wpe-labs:cache` | Purge object/page/CDN cache | 🟡 Write |
|
|
89
|
+
| `/wpe-labs:users` | List, invite, update roles, remove users | 🟡/🔴 |
|
|
90
|
+
| `/wpe-labs:domains` | Manage domains, DNS, SSL | 🟡/🔴 |
|
|
91
|
+
| `/wpe-labs:installs` | List, create, copy WordPress installs | 🟡/🔴 |
|
|
92
|
+
| `/wpe-labs:offload` | LargeFS media offload config | 🟡 Write |
|
|
93
|
+
|
|
94
|
+
Example prompts:
|
|
95
|
+
```
|
|
96
|
+
/wpe-labs:account-usage which accounts are closest to their bandwidth limit?
|
|
97
|
+
/wpe-labs:cache purge all cache for uofdev production
|
|
98
|
+
/wpe-labs:backups back up uofdev production before deployment
|
|
99
|
+
/wpe-labs:installs copy uofdev production to staging
|
|
100
|
+
/wpe-labs:monthly-report last month
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### 5) Re-installing wpe-labs skills
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
curl -fsSL https://raw.githubusercontent.com/wpengine/wpe-labs-platform-skills/main/install.sh | bash
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
## Verification
|
|
110
|
+
|
|
111
|
+
- SSH: `ssh git@git.wpengine.com info` — should return `hello <username> / R W <install>`
|
|
112
|
+
- API: `op run --env-file ~/.config/op-ssh/.env.1pass -- bash -c 'curl -s -u "$WPE_USERNAME:$WPE_PASSWORD" https://api.wpengineapi.com/v1/user | jq .email'`
|
|
113
|
+
|
|
114
|
+
## Failure modes
|
|
115
|
+
|
|
116
|
+
- **SSH: Host key verification failed** — re-run `ssh-keyscan git.wpengine.com >> ~/.ssh/known_hosts`
|
|
117
|
+
- **SSH: Permission denied** — confirm the key is at `~/.ssh/wpengine_ed25519` with `chmod 600`
|
|
118
|
+
- **git push rejected** — verify the remote URL matches the install name exactly
|
|
119
|
+
- **wpe-labs: 401 Unauthorized** — regenerate API credentials at `https://my.wpengine.com/api_access` and update the `WP Engine API` item in 1Password
|
|
120
|
+
- **wpe-labs: storage shows zero** — ask Claude to "refresh storage" (async recalculation, ~30–60s)
|
|
121
|
+
|
|
122
|
+
## References
|
|
123
|
+
|
|
124
|
+
- WP Engine git push portal: `https://my.wpengine.com/installs/<ENV>/git_push`
|
|
125
|
+
- WP Engine API access: `https://my.wpengine.com/api_access`
|
|
126
|
+
- wpe-labs skills source: `https://github.com/wpengine/wpe-labs-platform-skills`
|
|
127
|
+
- SSH setup log (first machine): gist `602d6a16ddfea438c0611a8e5cc31d5e`
|
package/README.md
CHANGED
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
[](LICENSE)
|
|
4
4
|
[](https://www.typescriptlang.org/)
|
|
5
|
-
[](package.json)
|
|
6
6
|
[](package.json)
|
|
7
7
|
[](.github/workflows/ci.yml)
|
|
8
8
|
|
|
9
|
-
**WordPress-focused AI agent starter kit** for GitHub Copilot, Cursor, Claude, and Pi Coding Agent. Installs
|
|
9
|
+
**WordPress-focused AI agent starter kit** for GitHub Copilot, Cursor, Claude, and Pi Coding Agent. Installs 17 specialized WordPress agent skills (plus an optional WP Engine skill), an agent persona, workflow instructions, and AGENTS.md configuration — everything an AI coding agent needs to build WordPress plugins, themes, and blocks correctly.
|
|
10
10
|
|
|
11
11
|
Maintained by [Kyle Brodeur](https://brodeur.me).
|
|
12
12
|
|
|
@@ -40,7 +40,7 @@ my-plugin/
|
|
|
40
40
|
│ ├── instructions/
|
|
41
41
|
│ │ └── wordpress-workflow.instructions.md
|
|
42
42
|
│ ├── prompts/
|
|
43
|
-
│ └── skills/ #
|
|
43
|
+
│ └── skills/ # 17 WordPress skills + 1 optional
|
|
44
44
|
│ ├── wp-project-triage/ # Project detection
|
|
45
45
|
│ ├── wp-plugin-development/ # Plugin architecture
|
|
46
46
|
│ ├── wp-block-development/ # Gutenberg blocks
|
|
@@ -51,9 +51,10 @@ my-plugin/
|
|
|
51
51
|
│ ├── wp-performance/ # Performance profiling
|
|
52
52
|
│ ├── wp-phpstan/ # Static analysis
|
|
53
53
|
│ ├── wp-wpcli-and-ops/ # WP-CLI operations
|
|
54
|
-
│ ├── wp-playground/ # Testing environments
|
|
54
|
+
│ ├── wp-playground/ # Testing environments (PHPUnit, Playwright, CI)
|
|
55
55
|
│ ├── wpds/ # Design system
|
|
56
|
-
│
|
|
56
|
+
│ ├── wordpress-router/ # Repo classification
|
|
57
|
+
│ └── wp-wpengine/ # (optional) WP Engine hosting + git push
|
|
57
58
|
└── .wp-agent-kit-manifest.github.json # Safe-update tracking
|
|
58
59
|
```
|
|
59
60
|
|
|
@@ -227,11 +228,10 @@ console.log(triage.data.project.primary); // "plugin"
|
|
|
227
228
|
|
|
228
229
|
## Skills Reference
|
|
229
230
|
|
|
230
|
-
All
|
|
231
|
+
All 17 skills follow the [AgentSkills.io](https://agentskills.io) specification. Skills in `skills-custom/` are project-specific (not from upstream) and survive `sync-skills`:
|
|
231
232
|
|
|
232
233
|
| Skill | When to Use |
|
|
233
234
|
|-------|------------|
|
|
234
|
-
| `wordpress-router` | Classify a WordPress repo and route to the right workflow |
|
|
235
235
|
| `wp-project-triage` | Run deterministic project detection (type, tooling, versions) |
|
|
236
236
|
| `wp-plugin-development` | Develop WordPress plugins (hooks, settings, security, release) |
|
|
237
237
|
| `wp-block-development` | Develop Gutenberg blocks (block.json, attributes, rendering) |
|
|
@@ -239,11 +239,17 @@ All 13 skills follow the [AgentSkills.io](https://agentskills.io) specification:
|
|
|
239
239
|
| `wp-rest-api` | Build, extend, or debug REST API endpoints/routes |
|
|
240
240
|
| `wp-interactivity-api` | Build Interactive blocks with data-wp-* directives |
|
|
241
241
|
| `wp-abilities-api` | Register and consume WordPress Abilities API |
|
|
242
|
+
| `wp-abilities-audit` | Audit a plugin's REST surface for Abilities API opportunities |
|
|
243
|
+
| `wp-abilities-verify` | Verify registered Abilities match their annotations |
|
|
242
244
|
| `wp-performance` | Profile and optimize WordPress performance |
|
|
243
245
|
| `wp-phpstan` | Configure and run PHPStan static analysis |
|
|
244
246
|
| `wp-wpcli-and-ops` | WP-CLI commands, automation, multisite operations |
|
|
245
|
-
| `wp-playground` | Test
|
|
247
|
+
| `wp-playground` | Test with disposable Playground instances; PHPUnit, Playwright E2E, CI |
|
|
248
|
+
| `blueprint` | Write and edit WordPress Playground blueprint JSON |
|
|
246
249
|
| `wpds` | Build UIs with the WordPress Design System |
|
|
250
|
+
| `wp-plugin-directory-guidelines` | GPL compliance, naming, slug rules for WP.org submission |
|
|
251
|
+
| `wordpress-router` | Route/classify repository type and select appropriate skills |
|
|
252
|
+
| **`wp-wpengine`** *(optional, custom)* | **WP Engine git push, install/domain/cache/backup management via wpe-labs skills** |
|
|
247
253
|
|
|
248
254
|
---
|
|
249
255
|
|
package/dist/lib/api.js
CHANGED
|
@@ -25,7 +25,7 @@ export async function installKitApi(options) {
|
|
|
25
25
|
installKit(targetDir, platform, { force, safe, backup });
|
|
26
26
|
return { success: true };
|
|
27
27
|
});
|
|
28
|
-
const filesCreated =
|
|
28
|
+
const filesCreated = getInstalledSummary(targetDir, platform);
|
|
29
29
|
const durationMs = Date.now() - startTime;
|
|
30
30
|
return formatter.success({
|
|
31
31
|
targetDir,
|
|
@@ -264,6 +264,19 @@ export async function syncSkillsApi(options = {}) {
|
|
|
264
264
|
fs.cpSync(sourceSkills, targetSkills, { recursive: true });
|
|
265
265
|
skillsSynced = fs.readdirSync(targetSkills).length;
|
|
266
266
|
}
|
|
267
|
+
// Merge custom skills (skills-custom/) — these are not part of the upstream
|
|
268
|
+
// WordPress/agent-skills repo and survive upstream syncs.
|
|
269
|
+
const customSkillsDir = path.join(PACKAGE_ROOT, 'skills-custom');
|
|
270
|
+
if (fs.existsSync(customSkillsDir)) {
|
|
271
|
+
for (const skillName of fs.readdirSync(customSkillsDir)) {
|
|
272
|
+
const src = path.join(customSkillsDir, skillName);
|
|
273
|
+
const dest = path.join(targetSkills, skillName);
|
|
274
|
+
if (fs.statSync(src).isDirectory()) {
|
|
275
|
+
fs.cpSync(src, dest, { recursive: true });
|
|
276
|
+
skillsSynced++;
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
}
|
|
267
280
|
return { success: true, skillsSynced, method };
|
|
268
281
|
});
|
|
269
282
|
return formatter.success({
|
|
@@ -473,38 +486,49 @@ function getPlatformFolder(platform) {
|
|
|
473
486
|
return folders[platform];
|
|
474
487
|
}
|
|
475
488
|
/**
|
|
476
|
-
* Get
|
|
489
|
+
* Get summary of installed files grouped by directory.
|
|
477
490
|
*/
|
|
478
|
-
function
|
|
491
|
+
function getInstalledSummary(targetDir, platform) {
|
|
479
492
|
const platformFolder = getPlatformFolder(platform);
|
|
480
|
-
const
|
|
493
|
+
const summary = [];
|
|
481
494
|
const targetPlatform = path.join(targetDir, platformFolder);
|
|
482
495
|
if (fs.existsSync(targetPlatform)) {
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
496
|
+
// Walk top-level entries for clean summary
|
|
497
|
+
const topEntries = fs.readdirSync(targetPlatform);
|
|
498
|
+
for (const entry of topEntries) {
|
|
499
|
+
const fullPath = path.join(targetPlatform, entry);
|
|
500
|
+
const stat = fs.statSync(fullPath);
|
|
501
|
+
if (stat.isDirectory()) {
|
|
502
|
+
let totalFiles = 0;
|
|
503
|
+
let totalDirs = 0;
|
|
504
|
+
function countAll(dir) {
|
|
505
|
+
const items = fs.readdirSync(dir);
|
|
506
|
+
for (const item of items) {
|
|
507
|
+
const itemPath = path.join(dir, item);
|
|
508
|
+
const s = fs.statSync(itemPath);
|
|
509
|
+
if (s.isDirectory()) {
|
|
510
|
+
totalDirs++;
|
|
511
|
+
countAll(itemPath);
|
|
512
|
+
}
|
|
513
|
+
else {
|
|
514
|
+
totalFiles++;
|
|
515
|
+
}
|
|
516
|
+
}
|
|
494
517
|
}
|
|
518
|
+
countAll(fullPath);
|
|
519
|
+
summary.push(`${platformFolder}/${entry}/ (${totalDirs + 1} dirs, ${totalFiles} files)`);
|
|
495
520
|
}
|
|
496
521
|
}
|
|
497
|
-
walk(targetPlatform);
|
|
498
522
|
}
|
|
499
523
|
const agentsPath = path.join(targetDir, 'AGENTS.md');
|
|
500
524
|
if (fs.existsSync(agentsPath)) {
|
|
501
|
-
|
|
525
|
+
summary.push('AGENTS.md');
|
|
502
526
|
}
|
|
503
527
|
const agentsTemplatePath = path.join(targetDir, 'AGENTS.template.md');
|
|
504
528
|
if (fs.existsSync(agentsTemplatePath)) {
|
|
505
|
-
|
|
529
|
+
summary.push('AGENTS.template.md');
|
|
506
530
|
}
|
|
507
|
-
return
|
|
531
|
+
return summary;
|
|
508
532
|
}
|
|
509
533
|
export { ExitCode } from '../utils/exit-codes.js';
|
|
510
534
|
export { OutputFormatter, createFormatter, parseOutputFormat } from '../utils/output.js';
|
package/dist/lib/installer.js
CHANGED
|
@@ -45,7 +45,6 @@ function isKitAlreadyInstalled(targetDir, platform) {
|
|
|
45
45
|
*/
|
|
46
46
|
function fullInstall(targetDir, platform, _force) {
|
|
47
47
|
const platformFolder = PLATFORM_FOLDERS[platform];
|
|
48
|
-
console.log(`Installing WordPress Agent Kit (${platform}) into: ${targetDir}`);
|
|
49
48
|
if (!fs.existsSync(targetDir)) {
|
|
50
49
|
fs.mkdirSync(targetDir, { recursive: true });
|
|
51
50
|
}
|
|
@@ -117,7 +116,6 @@ function fullInstall(targetDir, platform, _force) {
|
|
|
117
116
|
* Safe update install using the updater module.
|
|
118
117
|
*/
|
|
119
118
|
function safeUpdateInstall(targetDir, platform, options) {
|
|
120
|
-
console.log(`Updating WordPress Agent Kit (${platform}) in: ${targetDir}`);
|
|
121
119
|
const updateOptions = {
|
|
122
120
|
targetDir,
|
|
123
121
|
platform,
|