wordpress-agent-kit 0.3.2 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (135) hide show
  1. package/.agents/skills/blueprint/SKILL.md +418 -0
  2. package/.agents/skills/wordpress-router/SKILL.md +52 -0
  3. package/.agents/skills/wordpress-router/references/decision-tree.md +55 -0
  4. package/.agents/skills/wp-abilities-api/SKILL.md +108 -0
  5. package/.agents/skills/wp-abilities-api/references/delegate-helper-pattern.md +241 -0
  6. package/.agents/skills/wp-abilities-api/references/domain-vs-projection.md +113 -0
  7. package/.agents/skills/wp-abilities-api/references/error-code-vocabulary.md +123 -0
  8. package/.agents/skills/wp-abilities-api/references/grouping-heuristic.md +89 -0
  9. package/.agents/skills/wp-abilities-api/references/input-schema-gotchas.md +265 -0
  10. package/.agents/skills/wp-abilities-api/references/php-registration.md +94 -0
  11. package/.agents/skills/wp-abilities-api/references/plugin-family-patterns.md +233 -0
  12. package/.agents/skills/wp-abilities-api/references/rest-api.md +13 -0
  13. package/.agents/skills/wp-abilities-api/references/shared-core-service.md +184 -0
  14. package/.agents/skills/wp-abilities-audit/SKILL.md +199 -0
  15. package/.agents/skills/wp-abilities-audit/references/audit-schema.md +300 -0
  16. package/.agents/skills/wp-abilities-audit/references/capability-gate-tracing.md +197 -0
  17. package/.agents/skills/wp-abilities-audit/references/controller-enumeration.md +116 -0
  18. package/.agents/skills/wp-abilities-verify/SKILL.md +215 -0
  19. package/.agents/skills/wp-abilities-verify/references/annotation-correctness.md +154 -0
  20. package/.agents/skills/wp-abilities-verify/references/audit-schema-validation.md +131 -0
  21. package/.agents/skills/wp-abilities-verify/references/permission-roundtrip.md +190 -0
  22. package/.agents/skills/wp-abilities-verify/references/runtime-harness.md +462 -0
  23. package/.agents/skills/wp-abilities-verify/references/schema-lints.md +118 -0
  24. package/.agents/skills/wp-abilities-verify/references/static-enumeration.md +126 -0
  25. package/.agents/skills/wp-block-development/SKILL.md +175 -0
  26. package/.agents/skills/wp-block-development/references/attributes-and-serialization.md +22 -0
  27. package/.agents/skills/wp-block-development/references/block-json.md +49 -0
  28. package/.agents/skills/wp-block-development/references/creating-new-blocks.md +46 -0
  29. package/.agents/skills/wp-block-development/references/debugging.md +36 -0
  30. package/.agents/skills/wp-block-development/references/deprecations.md +24 -0
  31. package/.agents/skills/wp-block-development/references/dynamic-rendering.md +23 -0
  32. package/.agents/skills/wp-block-development/references/inner-blocks.md +25 -0
  33. package/.agents/skills/wp-block-development/references/registration.md +30 -0
  34. package/.agents/skills/wp-block-development/references/supports-and-wrappers.md +18 -0
  35. package/.agents/skills/wp-block-development/references/tooling-and-testing.md +21 -0
  36. package/.agents/skills/wp-block-development/scripts/list_blocks.mjs +121 -0
  37. package/.agents/skills/wp-block-themes/SKILL.md +117 -0
  38. package/.agents/skills/wp-block-themes/references/creating-new-block-theme.md +37 -0
  39. package/.agents/skills/wp-block-themes/references/debugging.md +24 -0
  40. package/.agents/skills/wp-block-themes/references/patterns.md +18 -0
  41. package/.agents/skills/wp-block-themes/references/style-variations.md +14 -0
  42. package/.agents/skills/wp-block-themes/references/templates-and-parts.md +16 -0
  43. package/.agents/skills/wp-block-themes/references/theme-json.md +59 -0
  44. package/.agents/skills/wp-block-themes/scripts/detect_block_themes.mjs +117 -0
  45. package/.agents/skills/wp-interactivity-api/SKILL.md +180 -0
  46. package/.agents/skills/wp-interactivity-api/references/debugging.md +29 -0
  47. package/.agents/skills/wp-interactivity-api/references/directives-quickref.md +30 -0
  48. package/.agents/skills/wp-interactivity-api/references/server-side-rendering.md +310 -0
  49. package/.agents/skills/wp-performance/SKILL.md +147 -0
  50. package/.agents/skills/wp-performance/references/autoload-options.md +24 -0
  51. package/.agents/skills/wp-performance/references/cron.md +20 -0
  52. package/.agents/skills/wp-performance/references/database.md +20 -0
  53. package/.agents/skills/wp-performance/references/http-api.md +15 -0
  54. package/.agents/skills/wp-performance/references/measurement.md +21 -0
  55. package/.agents/skills/wp-performance/references/object-cache.md +24 -0
  56. package/.agents/skills/wp-performance/references/query-monitor-headless.md +38 -0
  57. package/.agents/skills/wp-performance/references/server-timing.md +22 -0
  58. package/.agents/skills/wp-performance/references/wp-cli-doctor.md +24 -0
  59. package/.agents/skills/wp-performance/references/wp-cli-profile.md +32 -0
  60. package/.agents/skills/wp-performance/scripts/perf_inspect.mjs +128 -0
  61. package/.agents/skills/wp-phpstan/SKILL.md +98 -0
  62. package/.agents/skills/wp-phpstan/references/configuration.md +52 -0
  63. package/.agents/skills/wp-phpstan/references/third-party-classes.md +76 -0
  64. package/.agents/skills/wp-phpstan/references/wordpress-annotations.md +124 -0
  65. package/.agents/skills/wp-phpstan/scripts/phpstan_inspect.mjs +263 -0
  66. package/.agents/skills/wp-playground/SKILL.md +233 -0
  67. package/.agents/skills/wp-playground/references/blueprints.md +36 -0
  68. package/.agents/skills/wp-playground/references/cli-commands.md +39 -0
  69. package/.agents/skills/wp-playground/references/debugging.md +16 -0
  70. package/.agents/skills/wp-playground/references/e2e-playwright.md +115 -0
  71. package/.agents/skills/wp-plugin-development/SKILL.md +113 -0
  72. package/.agents/skills/wp-plugin-development/references/data-and-cron.md +19 -0
  73. package/.agents/skills/wp-plugin-development/references/debugging.md +19 -0
  74. package/.agents/skills/wp-plugin-development/references/lifecycle.md +33 -0
  75. package/.agents/skills/wp-plugin-development/references/security.md +29 -0
  76. package/.agents/skills/wp-plugin-development/references/settings-api.md +22 -0
  77. package/.agents/skills/wp-plugin-development/references/structure.md +16 -0
  78. package/.agents/skills/wp-plugin-development/scripts/detect_plugins.mjs +122 -0
  79. package/.agents/skills/wp-plugin-directory-guidelines/SKILL.md +133 -0
  80. package/.agents/skills/wp-plugin-directory-guidelines/references/gpl-compliance.md +217 -0
  81. package/.agents/skills/wp-plugin-directory-guidelines/references/guideline-review-checklist.md +592 -0
  82. package/.agents/skills/wp-plugin-directory-guidelines/references/naming-rules.md +121 -0
  83. package/.agents/skills/wp-project-triage/SKILL.md +39 -0
  84. package/.agents/skills/wp-project-triage/references/triage.schema.json +143 -0
  85. package/.agents/skills/wp-project-triage/scripts/detect_wp_project.mjs +610 -0
  86. package/.agents/skills/wp-rest-api/SKILL.md +115 -0
  87. package/.agents/skills/wp-rest-api/references/authentication.md +18 -0
  88. package/.agents/skills/wp-rest-api/references/custom-content-types.md +20 -0
  89. package/.agents/skills/wp-rest-api/references/discovery-and-params.md +20 -0
  90. package/.agents/skills/wp-rest-api/references/responses-and-fields.md +30 -0
  91. package/.agents/skills/wp-rest-api/references/routes-and-endpoints.md +36 -0
  92. package/.agents/skills/wp-rest-api/references/schema.md +22 -0
  93. package/.agents/skills/wp-wpcli-and-ops/SKILL.md +126 -0
  94. package/.agents/skills/wp-wpcli-and-ops/references/automation.md +30 -0
  95. package/.agents/skills/wp-wpcli-and-ops/references/cron-and-cache.md +23 -0
  96. package/.agents/skills/wp-wpcli-and-ops/references/debugging.md +17 -0
  97. package/.agents/skills/wp-wpcli-and-ops/references/multisite.md +22 -0
  98. package/.agents/skills/wp-wpcli-and-ops/references/packages-and-updates.md +22 -0
  99. package/.agents/skills/wp-wpcli-and-ops/references/safety.md +30 -0
  100. package/.agents/skills/wp-wpcli-and-ops/references/search-replace.md +40 -0
  101. package/.agents/skills/wp-wpcli-and-ops/scripts/wpcli_inspect.mjs +90 -0
  102. package/.agents/skills/wp-wpengine/SKILL.md +398 -0
  103. package/.agents/skills/wp-wpengine/references/ci-gate.md +469 -0
  104. package/.agents/skills/wp-wpengine/references/github-actions-deploy.md +736 -0
  105. package/.agents/skills/wp-wpengine/scripts/ci-gate.sh +118 -0
  106. package/.agents/skills/wp-wpengine/scripts/wpe-check.sh +89 -0
  107. package/.agents/skills/wp-wpengine/scripts/wpe-preflight.sh +104 -0
  108. package/.agents/skills/wpds/SKILL.md +59 -0
  109. package/.github/agents/wp-architect.agent.md +1 -2
  110. package/.github/copilot-instructions.md +1 -1
  111. package/.github/instructions/wordpress-workflow.instructions.md +3 -3
  112. package/.github/skills/wp-playground/SKILL.md +132 -1
  113. package/.github/skills/wp-playground/references/e2e-playwright.md +115 -0
  114. package/.github/skills/wp-wpengine/SKILL.md +127 -0
  115. package/AGENTS.md +22 -10
  116. package/AGENTS.template.md +20 -10
  117. package/README.md +93 -86
  118. package/dist/cli.js +5 -1
  119. package/dist/commands/clean-skills.js +64 -0
  120. package/dist/commands/setup.js +6 -2
  121. package/dist/commands/sync-skills.js +3 -0
  122. package/dist/lib/api.js +176 -4
  123. package/dist/lib/installer.js +166 -2
  124. package/extensions/wp-agent-kit/index.ts +185 -10
  125. package/package.json +10 -14
  126. package/skills-custom/wp-wpengine/SKILL.md +398 -0
  127. package/skills-custom/wp-wpengine/references/ci-gate.md +469 -0
  128. package/skills-custom/wp-wpengine/references/github-actions-deploy.md +736 -0
  129. package/skills-custom/wp-wpengine/scripts/ci-gate.sh +118 -0
  130. package/skills-custom/wp-wpengine/scripts/wpe-check.sh +89 -0
  131. package/skills-custom/wp-wpengine/scripts/wpe-preflight.sh +104 -0
  132. package/.github/workflows/ci.yml +0 -44
  133. package/.husky/pre-commit +0 -7
  134. package/CLI_REVIEW.md +0 -250
  135. package/biome.json +0 -39
@@ -0,0 +1,124 @@
1
+ # WordPress-specific type annotations
2
+
3
+ These patterns help PHPStan understand WordPress code where runtime behavior and dynamic typing make inference difficult.
4
+
5
+ ## REST API request typing
6
+
7
+ PHPStan cannot infer valid request parameters from REST API schemas. Provide explicit type hints for request params.
8
+
9
+ ```php
10
+ /**
11
+ * Handle REST API request.
12
+ *
13
+ * @param WP_REST_Request $request Full details about the request.
14
+ * @return WP_REST_Response|WP_Error Response object on success, error on failure.
15
+ *
16
+ * @phpstan-param WP_REST_Request<array{
17
+ * post?: int,
18
+ * orderby?: string,
19
+ * meta_key?: string,
20
+ * per_page?: int,
21
+ * status?: array<string>
22
+ * }> $request
23
+ */
24
+ public function get_items( $request ) {
25
+ $post_id = $request->get_param( 'post' );
26
+ // PHPStan now knows $post_id is int|null.
27
+ }
28
+ ```
29
+
30
+ For complex schemas, define reusable types.
31
+
32
+ ```php
33
+ /**
34
+ * @phpstan-type PostRequestParams array{
35
+ * title?: string,
36
+ * content?: string,
37
+ * status?: 'publish'|'draft'|'private',
38
+ * meta?: array<string, mixed>
39
+ * }
40
+ *
41
+ * @phpstan-param WP_REST_Request<PostRequestParams> $request
42
+ */
43
+ ```
44
+
45
+ ## Hook callbacks
46
+
47
+ ```php
48
+ /**
49
+ * Handle status transitions.
50
+ *
51
+ * @param string $new_status
52
+ * @param string $old_status
53
+ * @param WP_Post $post
54
+ */
55
+ function handle_transition( string $new_status, string $old_status, WP_Post $post ): void {
56
+ // ...
57
+ }
58
+
59
+ add_action( 'transition_post_status', 'handle_transition', 10, 3 );
60
+ ```
61
+
62
+ ## Database and iterables
63
+
64
+ ```php
65
+ /**
66
+ * @return array<WP_Post> WP_Post objects.
67
+ */
68
+ function get_custom_posts(): array {
69
+ $posts = get_posts( [ 'post_type' => 'custom_type', 'numberposts' => -1 ] );
70
+ return $posts;
71
+ }
72
+
73
+ /**
74
+ * @return array<object{id: int, name: string}> Database results.
75
+ */
76
+ function get_user_data(): array {
77
+ global $wpdb;
78
+
79
+ $results = $wpdb->get_results( "SELECT id, name FROM users", OBJECT );
80
+ return $results ?: [];
81
+ }
82
+ ```
83
+
84
+ ## Hooks (`apply_filters()` and `do_action()`)
85
+
86
+ Docblocks for `apply_filters()` and `do_action()` are validated. The type of the first `@param` is definitive.
87
+
88
+ If a third party returns the wrong type for a filter, a PHPStan error is expected and does not require defensive code.
89
+
90
+ ```php
91
+ /**
92
+ * Allows hooking into formatting of the price.
93
+ *
94
+ * @param string $formatted The formatted price.
95
+ * @param float $price The raw price.
96
+ * @param string $locale Locale to localize pricing display.
97
+ * @param string $currency Currency symbol.
98
+ */
99
+ return apply_filters( 'autoscout_vehicle_price_formatted', $formatted, $price, $locale, $currency );
100
+ ```
101
+
102
+ ## Action Scheduler argument shapes
103
+
104
+ ```php
105
+ /**
106
+ * Process a scheduled email.
107
+ *
108
+ * @param array{user_id: int, email: string, data: array<string, mixed>} $args
109
+ */
110
+ function process_scheduled_email( array $args ): void {
111
+ $user_id = $args['user_id'];
112
+ // ...
113
+ }
114
+
115
+ as_schedule_single_action(
116
+ time() + 3600,
117
+ 'process_scheduled_email',
118
+ [
119
+ 'user_id' => 123,
120
+ 'email' => 'user@example.com',
121
+ 'data' => [ 'key' => 'value' ],
122
+ ]
123
+ );
124
+ ```
@@ -0,0 +1,263 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+
4
+ const TOOL_VERSION = "0.1.0";
5
+
6
+ /**
7
+ * Reads and parses JSON from a file path.
8
+ *
9
+ * Returns null when parsing fails so the caller can provide user-facing
10
+ * guidance without crashing.
11
+ *
12
+ * @param {string} filePath Absolute path to a JSON file.
13
+ * @returns {any|null} Parsed JSON object.
14
+ */
15
+ function readJsonSafe(filePath) {
16
+ try {
17
+ return JSON.parse(fs.readFileSync(filePath, "utf8"));
18
+ } catch {
19
+ return null;
20
+ }
21
+ }
22
+
23
+ /**
24
+ * Reads a UTF-8 text file.
25
+ *
26
+ * Returns null when reading fails so callers can surface missing configs
27
+ * without crashing.
28
+ *
29
+ * @param {string} filePath Absolute path to a text file.
30
+ * @returns {string|null} File contents.
31
+ */
32
+ function readTextSafe(filePath) {
33
+ try {
34
+ return fs.readFileSync(filePath, "utf8");
35
+ } catch {
36
+ return null;
37
+ }
38
+ }
39
+
40
+ /**
41
+ * Checks whether a path exists and is a regular file.
42
+ *
43
+ * @param {string} filePath Absolute or relative file path.
44
+ * @returns {boolean} True when the path exists and is a file.
45
+ */
46
+ function isFile(filePath) {
47
+ try {
48
+ return fs.statSync(filePath).isFile();
49
+ } catch {
50
+ return false;
51
+ }
52
+ }
53
+
54
+ /**
55
+ * Normalizes Composer script entries into a flat list of commands.
56
+ *
57
+ * Composer allows scripts to be strings or arrays. This helper provides a
58
+ * consistent format for analysis.
59
+ *
60
+ * @param {unknown} value Composer script value.
61
+ * @returns {string[]} Command list.
62
+ */
63
+ function normalizeComposerScript(value) {
64
+ if (typeof value === "string") return [value];
65
+ if (Array.isArray(value)) return value.filter((x) => typeof x === "string");
66
+ return [];
67
+ }
68
+
69
+ /**
70
+ * Detects which Composer scripts invoke PHPStan.
71
+ *
72
+ * This helps the agent prefer the repo's own invocation (memory limits,
73
+ * config, bootstrap files) instead of guessing.
74
+ *
75
+ * @param {Record<string, unknown>} scripts Composer scripts block.
76
+ * @returns {Array<{name: string, commands: string[]}>} Matching script entries.
77
+ */
78
+ function findPhpstanScripts(scripts) {
79
+ if (!scripts || typeof scripts !== "object") return [];
80
+
81
+ const matches = [];
82
+
83
+ for (const [name, raw] of Object.entries(scripts)) {
84
+ const commands = normalizeComposerScript(raw);
85
+
86
+ const invokesPhpstan = commands.some((cmd) => {
87
+ if (typeof cmd !== "string") return false;
88
+ return cmd.includes("phpstan") || cmd.includes("vendor/bin/phpstan");
89
+ });
90
+
91
+ if (!invokesPhpstan) continue;
92
+
93
+ matches.push({ name, commands });
94
+ }
95
+
96
+ return matches;
97
+ }
98
+
99
+ /**
100
+ * Chooses a recommended command for running PHPStan in the current repo.
101
+ *
102
+ * The intent is to prefer an existing Composer script (often has correct
103
+ * config, bootstrap, and memory limits), falling back to vendor binaries.
104
+ *
105
+ * @param {Array<{name: string, commands: string[]}>} phpstanScripts Matching Composer scripts.
106
+ * @param {{binaryRelPath: string|null, configRelPath: string|null}} fallbackInfo Fallback discovery.
107
+ * @returns {{command: string|null, rationale: string}} Suggested command and why.
108
+ */
109
+ function suggestCommand(phpstanScripts, fallbackInfo) {
110
+ const preferred = phpstanScripts.find((s) => s.name === "phpstan");
111
+ if (preferred) {
112
+ return {
113
+ command: `composer run ${preferred.name}`,
114
+ rationale: "Uses the repo's Composer script (preferred for consistent config).",
115
+ };
116
+ }
117
+
118
+ if (phpstanScripts.length > 0) {
119
+ return {
120
+ command: `composer run ${phpstanScripts[0].name}`,
121
+ rationale: "Uses the repo's Composer script that invokes PHPStan.",
122
+ };
123
+ }
124
+
125
+ if (!fallbackInfo.binaryRelPath) {
126
+ return {
127
+ command: null,
128
+ rationale: "No PHPStan binary detected under vendor/bin and no Composer script found.",
129
+ };
130
+ }
131
+
132
+ const configArg = fallbackInfo.configRelPath ? ` -c ${fallbackInfo.configRelPath}` : "";
133
+
134
+ return {
135
+ command: `${fallbackInfo.binaryRelPath} analyse${configArg}`,
136
+ rationale: "Falls back to vendor/bin/phpstan with an explicit config when needed.",
137
+ };
138
+ }
139
+
140
+ /**
141
+ * Extracts lightweight hints from a phpstan.neon config.
142
+ *
143
+ * This does not parse NEON. It only checks for common directive tokens so the
144
+ * agent can quickly see whether scan directives are in use.
145
+ *
146
+ * @param {string} configText Raw phpstan config contents.
147
+ * @returns {{mentionsScanDirectories: boolean, mentionsScanFiles: boolean}} Hints.
148
+ */
149
+ function buildConfigHints(configText) {
150
+ const t = configText.toLowerCase();
151
+
152
+ return {
153
+ mentionsScanDirectories: t.includes("scandirectories"),
154
+ mentionsScanFiles: t.includes("scanfiles"),
155
+ };
156
+ }
157
+
158
+ /**
159
+ * Extracts stub-like package references from a PHPStan config.
160
+ *
161
+ * The PHPStan config usually references stubs via vendor paths (for example,
162
+ * "vendor/php-stubs/wordpress-stubs"), so this helper focuses on composer-style
163
+ * "vendor/package" tokens containing "stubs".
164
+ *
165
+ * @param {string} configText Raw phpstan config contents.
166
+ * @returns {string[]} Unique, lowercased composer-style package references.
167
+ */
168
+ function extractStubPackageReferences(configText) {
169
+ const matches = configText
170
+ .toLowerCase()
171
+ .match(/\b[a-z0-9_.-]+\/[a-z0-9_.-]*stubs[a-z0-9_.-]*\b/g);
172
+
173
+ if (!matches) return [];
174
+
175
+ return [...new Set(matches)].sort();
176
+ }
177
+
178
+ /**
179
+ * Builds a JSON report describing the current repository's PHPStan setup.
180
+ *
181
+ * @returns {object} A stable, machine-readable inspection report.
182
+ */
183
+ function buildReport() {
184
+ const repoRoot = process.cwd();
185
+
186
+ const composerPath = path.join(repoRoot, "composer.json");
187
+ const composer = isFile(composerPath) ? readJsonSafe(composerPath) : null;
188
+
189
+ const phpstanConfigFiles = ["phpstan.neon", "phpstan.neon.dist"].filter((f) =>
190
+ isFile(path.join(repoRoot, f))
191
+ );
192
+ const phpstanBaselineFiles = ["phpstan-baseline.neon", "phpstan-baseline.neon.dist"].filter((f) =>
193
+ isFile(path.join(repoRoot, f))
194
+ );
195
+
196
+ let configRelPath = null;
197
+ if (phpstanConfigFiles.includes("phpstan.neon")) configRelPath = "phpstan.neon";
198
+ else if (phpstanConfigFiles.includes("phpstan.neon.dist")) configRelPath = "phpstan.neon.dist";
199
+
200
+ const configAbsPath = configRelPath ? path.join(repoRoot, configRelPath) : null;
201
+ const configText = configAbsPath ? readTextSafe(configAbsPath) : null;
202
+
203
+ const binaryRelPath = isFile(path.join(repoRoot, "vendor", "bin", "phpstan")) ? "vendor/bin/phpstan" : null;
204
+
205
+ const composerScripts = composer?.scripts && typeof composer.scripts === "object" ? composer.scripts : null;
206
+ const phpstanScripts = composerScripts ? findPhpstanScripts(composerScripts) : [];
207
+
208
+ const composerDependencies = [
209
+ ...Object.keys(composer?.require ?? {}),
210
+ ...Object.keys(composer?.["require-dev"] ?? {}),
211
+ ].sort();
212
+ const referencedDependencies = configText ? extractStubPackageReferences(configText) : [];
213
+
214
+ const configHints = configText ? buildConfigHints(configText) : null;
215
+
216
+ const suggested = suggestCommand(phpstanScripts, {
217
+ binaryRelPath,
218
+ configRelPath: configRelPath === "phpstan.neon" ? null : configRelPath,
219
+ });
220
+
221
+ const notes = [];
222
+
223
+ if (!composer) notes.push("No composer.json found; PHPStan is usually installed via Composer.");
224
+ if (phpstanConfigFiles.length === 0) notes.push("No phpstan.neon or phpstan.neon.dist found at repo root.");
225
+ if (!binaryRelPath && phpstanScripts.length === 0) notes.push("No PHPStan entrypoint detected (Composer script or vendor/bin/phpstan).");
226
+
227
+
228
+
229
+ return {
230
+ tool: { name: "phpstan_inspect", version: TOOL_VERSION },
231
+ repoRoot,
232
+ composer: {
233
+ exists: Boolean(composer),
234
+ path: isFile(composerPath) ? "composer.json" : null,
235
+ phpstanScripts,
236
+ dependencies: composerDependencies,
237
+ },
238
+ phpstan: {
239
+ configFiles: phpstanConfigFiles,
240
+ baselineFiles: phpstanBaselineFiles,
241
+ config: {
242
+ primary: configRelPath,
243
+ hints: configHints,
244
+ referencedDependencies,
245
+ },
246
+ binary: {
247
+ vendorBin: binaryRelPath,
248
+ },
249
+ },
250
+ suggested,
251
+ notes,
252
+ };
253
+ }
254
+
255
+ /**
256
+ * CLI entrypoint for printing the inspection report.
257
+ */
258
+ function main() {
259
+ const report = buildReport();
260
+ process.stdout.write(`${JSON.stringify(report, null, 2)}\n`);
261
+ }
262
+
263
+ main();
@@ -0,0 +1,233 @@
1
+ ---
2
+ name: wp-playground
3
+ description: "Use for WordPress Playground workflows: fast disposable WP instances in the browser or locally via @wp-playground/cli (server, run-blueprint, build-snapshot), auto-mounting plugins/themes, switching WP/PHP versions, blueprints, PHPUnit testing, E2E Playwright testing, programmatic runCLI API, and debugging (Xdebug)."
4
+ license: GPL-2.0-or-later
5
+ compatibility: "Targets WordPress 6.9+ (PHP 7.2.24+). Playground CLI requires Node.js 20.18+; runs WP in WebAssembly with SQLite."
6
+ ---
7
+
8
+ # WordPress Playground
9
+
10
+ ## When to use
11
+
12
+ - Spin up a disposable WordPress to test a plugin/theme without full stack setup.
13
+ - Run or iterate on Playground Blueprints (JSON) locally.
14
+ - Build a reproducible snapshot of a site for sharing or CI.
15
+ - Switch WP/PHP versions quickly to reproduce issues.
16
+ - Debug plugin/theme code with Xdebug in an isolated Playground.
17
+ - Run PHPUnit tests without a local database (no Docker, no MySQL).
18
+ - Write E2E Playwright tests against a real WordPress instance.
19
+ - Automate Playground in CI/CD pipelines via the programmatic `runCLI` API.
20
+
21
+ ## Inputs required
22
+
23
+ - Host machine readiness: Node.js ≥ 20.18, `npm`/`npx` available.
24
+ - Project path to mount (`--auto-mount` or explicit mount mapping).
25
+ - Desired WP version/PHP version (optional; defaults to latest WP, PHP 8.3).
26
+ - Blueprint location/URL if running a blueprint.
27
+ - Port preference if 9400 conflicts.
28
+ - Whether Xdebug is needed.
29
+
30
+ ## Procedure
31
+
32
+ ### 0) Guardrails
33
+
34
+ - Playground instances are ephemeral and SQLite-backed; **never** point at production data.
35
+ - Confirm Node ≥ 20.18 (`node -v`) before running CLI.
36
+ - If mounting local code, ensure it is clean of secrets; Playground copies files into an in-memory FS.
37
+
38
+ ### 1) Quick local spin-up (auto-mount)
39
+
40
+ ```bash
41
+ cd <plugin-or-theme-root>
42
+ npx @wp-playground/cli@latest server --auto-mount
43
+ ```
44
+ - Opens on http://localhost:9400 by default. Auto-detects plugin/theme and installs it.
45
+ - Add `--wp=<version>` / `--php=<version>` as needed.
46
+ - For classic full installs already present, add `--skip-wordpress-setup` and mount the whole tree.
47
+
48
+ ### 2) Manual mounts or multiple mounts
49
+
50
+ - Use `--mount=/host/path:/vfs/path` (repeatable) when auto-mount is insufficient (multi-plugin, mu-plugins, custom content).
51
+ - Mount before install with `--mount-before-install` for bootstrapping installer flows.
52
+ - Reference: `references/cli-commands.md`
53
+
54
+ ### 3) Run a Blueprint (no server needed)
55
+
56
+ ```bash
57
+ npx @wp-playground/cli@latest run-blueprint --blueprint=<file-or-url>
58
+ ```
59
+ - Use for scripted setup/CI validation. Supports remote URLs and local files.
60
+ - Allow bundled assets in local blueprints with `--blueprint-may-read-adjacent-files` when required.
61
+ - See `references/blueprints.md` for structure and common flags.
62
+
63
+ ### 4) Build a snapshot for sharing
64
+
65
+ ```bash
66
+ npx @wp-playground/cli@latest build-snapshot --blueprint=<file> --outfile=./site.zip
67
+ ```
68
+ - Produces a ZIP you can load in Playground or attach to bug reports.
69
+
70
+ ### 5) Debugging with Xdebug
71
+
72
+ - Start with `--xdebug` (or `--enable-xdebug` depending on CLI release) to expose an IDE key, then connect VS Code/PhpStorm to the host/port shown in CLI output.
73
+ - Combine with `--auto-mount` for plugin/theme debugging.
74
+ - Checklist: `references/debugging.md`
75
+
76
+ ### 6) Version switching
77
+
78
+ - Use `--wp=` to pin WP (e.g., 6.9.0) and `--php=` to test compatibility.
79
+ - If feature depends on Gutenberg trunk, prefer the latest WP release plus plugin if available; Playground images track stable WP plus bundled Gutenberg.
80
+
81
+ ### 7) Browser-only workflows (no CLI)
82
+
83
+ - Launch quick previews with URL fragments or query params:
84
+ - Fragment: `https://playground.wordpress.net/#<base64-or-json-blueprint>`
85
+ - Query: `https://playground.wordpress.net/?blueprint-url=<public-url-or-zip>`
86
+ - Use the live Blueprint Editor (playground.wordpress.net) to author blueprints with schema help; paste JSON and copy a shareable link.
87
+
88
+ ### 8) PHPUnit testing (no database required)
89
+
90
+ Run PHPUnit inside Playground — every run starts with a clean WordPress install, fully isolated.
91
+
92
+ Plugin:
93
+ ```bash
94
+ npx @wp-playground/cli@latest php \
95
+ --auto-mount \
96
+ -- \
97
+ /wordpress/wp-content/plugins/MY_PLUGIN/vendor/bin/phpunit \
98
+ -c /wordpress/wp-content/plugins/MY_PLUGIN/phpunit.xml.dist
99
+ ```
100
+
101
+ Theme (replace `plugins/` with `themes/`):
102
+ ```bash
103
+ npx @wp-playground/cli@latest php \
104
+ --auto-mount \
105
+ -- \
106
+ /wordpress/wp-content/themes/MY_THEME/vendor/bin/phpunit \
107
+ -c /wordpress/wp-content/themes/MY_THEME/phpunit.xml.dist
108
+ ```
109
+
110
+ - Requires PHPUnit installed via Composer in the project (`composer require --dev phpunit/phpunit`).
111
+ - `--auto-mount` maps the current directory to the correct WP content path automatically.
112
+ - Use `--php=8.1 --wp=6.5` flags to test against specific versions (PHP 7.4–8.5 supported).
113
+ - Explicit mount: `--mount=.:/wordpress/wp-content/plugins/MY_PLUGIN`.
114
+
115
+ ### 9) E2E testing with Playwright
116
+
117
+ Use `runCLI` from `@wp-playground/cli` to start a Playground server programmatically in Playwright tests. No Docker, no database.
118
+
119
+ Install:
120
+ ```bash
121
+ npm install --save-dev @playwright/test @wp-playground/cli
122
+ npx playwright install chromium
123
+ ```
124
+
125
+ Minimal `playwright.config.ts`:
126
+ ```ts
127
+ import { defineConfig } from '@playwright/test';
128
+ export default defineConfig({
129
+ testDir: './tests/e2e',
130
+ fullyParallel: false,
131
+ workers: 1, // prevent port conflicts
132
+ timeout: 120_000, // WP boot takes time
133
+ expect: { timeout: 30_000 },
134
+ use: { screenshot: 'only-on-failure', trace: 'on-first-retry' },
135
+ });
136
+ ```
137
+
138
+ First test (`tests/e2e/plugin.spec.ts`):
139
+ ```ts
140
+ import { test, expect } from '@playwright/test';
141
+ import { runCLI } from '@wp-playground/cli';
142
+
143
+ let cli: Awaited<ReturnType<typeof runCLI>>;
144
+
145
+ test.beforeAll(async () => {
146
+ cli = await runCLI({
147
+ command: 'server',
148
+ blueprint: {
149
+ preferredVersions: { php: '8.3', wp: 'latest' },
150
+ login: true,
151
+ },
152
+ });
153
+ });
154
+
155
+ test.afterAll(async () => { await cli?.server?.close(); });
156
+
157
+ test('dashboard loads', async ({ page }) => {
158
+ await page.goto(`${cli.serverUrl}/wp-admin/`);
159
+ await expect(page.locator('#wpbody-content')).toBeVisible();
160
+ });
161
+ ```
162
+
163
+ Mount a local plugin:
164
+ ```ts
165
+ cli = await runCLI({
166
+ command: 'server',
167
+ mount: { './': '/wordpress/wp-content/plugins/my-plugin' },
168
+ blueprint: {
169
+ preferredVersions: { php: '8.3', wp: 'latest' },
170
+ login: true,
171
+ steps: [{ step: 'activatePlugin', pluginPath: 'my-plugin/my-plugin.php' }],
172
+ },
173
+ });
174
+ ```
175
+
176
+ Locator priority (most to least preferred):
177
+ 1. `page.getByRole()` — buttons, headings, links, inputs
178
+ 2. `page.getByLabel()` — labeled form fields
179
+ 3. `page.getByText()` — visible text
180
+ 4. `page.getByTestId()` — your own `data-testid` attributes
181
+ 5. `page.locator()` — CSS/XPath last resort (WP core layout elements like `#wpadminbar`)
182
+
183
+ Version matrix pattern:
184
+ ```ts
185
+ const matrix = [{ php: '8.1', wp: '6.5' }, { php: '8.3', wp: 'latest' }];
186
+ for (const { php, wp } of matrix) {
187
+ test.describe(`PHP ${php} + WP ${wp}`, () => {
188
+ // ... beforeAll/afterAll with those versions
189
+ });
190
+ }
191
+ ```
192
+
193
+ CI (GitHub Actions): see `references/e2e-playwright.md`.
194
+
195
+ ### 10) Programmatic `runCLI` API (scripts / Vitest integration)
196
+
197
+ ```ts
198
+ import { runCLI } from '@wp-playground/cli';
199
+
200
+ const server = await runCLI({
201
+ command: 'server',
202
+ php: '8.3',
203
+ wp: 'latest',
204
+ login: true,
205
+ mount: [{ hostPath: './my-plugin', vfsPath: '/wordpress/wp-content/plugins/my-plugin' }],
206
+ blueprint: { steps: [{ step: 'activatePlugin', pluginPath: 'my-plugin/plugin.php' }] },
207
+ });
208
+
209
+ // server.serverUrl — the base URL
210
+ // server.server — the HTTP server instance (call .close() in afterEach)
211
+ // server[Symbol.asyncDispose]() — cleanup in Vitest afterEach
212
+ ```
213
+
214
+ Use `wordpressInstallMode: 'do-not-attempt-installing'` + `skipSqliteSetup: true` when testing pure PHP with no WordPress overhead.
215
+
216
+ ## Verification
217
+
218
+ - Verify mounted code is active (plugin listed/active; theme selected).
219
+ - For blueprints/snapshots, re-run with `--verbosity=debug` to confirm steps executed.
220
+ - Run targeted smoke (e.g., `wp plugin list` inside Playground shell via browser terminal if exposed) or UI click-path.
221
+
222
+ ## Failure modes / debugging
223
+
224
+ - **CLI exits complaining about Node**: upgrade to ≥ 20.18.
225
+ - **Mount not applied**: check path, use absolute path, add `--verbosity=debug`.
226
+ - **Blueprint cannot read local assets**: add `--blueprint-may-read-adjacent-files`.
227
+ - **Port already used**: `--port=<free-port>`.
228
+ - **Slow/locked UI**: disable `--experimental-multi-worker` if enabled; or enable it to improve throughput on CPU-bound runs.
229
+
230
+ ## Escalation
231
+
232
+ - If PHP extensions or native DB access are required, Playground may be unsuitable; fall back to full WP stack or wp-env/Docker.
233
+ - For browser-only embedding or VS Code extension specifics, consult the upstream docs: https://wordpress.github.io/wordpress-playground/
@@ -0,0 +1,36 @@
1
+ ## Blueprint quick reference
2
+
3
+ Blueprints are JSON recipes that describe how Playground should set up WordPress.
4
+
5
+ ### Minimal example
6
+
7
+ ```json
8
+ {
9
+ "$schema": "https://playground.wordpress.net/blueprint-schema.json",
10
+ "steps": [
11
+ { "step": "installTheme", "themeZipUrl": "https://downloads.wordpress.org/theme/twentytwentythree.zip" },
12
+ { "step": "installPlugin", "pluginZipUrl": "https://downloads.wordpress.org/plugin/classic-editor.zip" }
13
+ ]
14
+ }
15
+ ```
16
+
17
+ ### Common steps (non-exhaustive)
18
+
19
+ - `setSiteUrl`, `setHomeUrl`
20
+ - `installTheme`, `installPlugin` (ZIP URLs or local paths when allowed)
21
+ - `activateTheme`, `activatePlugin`
22
+ - `runPHP` (inline PHP)
23
+ - `applyPatches` (filesystem patch)
24
+ - `writeFile` (create/update files)
25
+ - `importFile` (XML/WXR)
26
+ - `wpConfigConstants` (define constants)
27
+ - `preferredVersions` (pick WP/PHP; matches CLI `--wp` / `--php`)
28
+ - `blueprintSteps` that include `extraLibraries` (e.g., Jetpack) and `features.networking` when browser networking is required
29
+
30
+ ### Tips
31
+
32
+ - Use `--blueprint-may-read-adjacent-files` when the blueprint needs local files (e.g., custom plugin ZIP) during `run-blueprint` or `build-snapshot`.
33
+ - For iterative authoring, keep blueprints small and compose via separate files.
34
+ - Validate against the published schema URL above to catch typos.
35
+ - For Gutenberg/nightly testing, set `--wp=<version>` to align with target WP.
36
+ - To share quickly, encode the blueprint as base64 in the Playground URL fragment or host the JSON/ZIP and pass `?blueprint-url=…`.
@@ -0,0 +1,39 @@
1
+ ## Playground CLI command cheatsheet
2
+
3
+ > Requires Node.js 20.18+ and npm/npx.
4
+ > Latest version: 3.0.20 (November 2025)
5
+
6
+ ### What's new in 2025
7
+
8
+ - **PHP 8.3 is now the default** (since July 2025).
9
+ - **New PHP extensions**: ImageMagick, SOAP, and AVIF GD support.
10
+ - **OpCache enabled**: 42% faster response times (185ms → 108ms average).
11
+ - **Multi-worker default**: `--experimental-multi-worker` now defaults to CPU count minus one.
12
+
13
+ ### Install / run server
14
+
15
+ - `npx @wp-playground/cli@latest server [--port=9400] [--auto-mount] [--wp=<ver>] [--php=<ver>] [--verbosity=debug] [--blueprint=<url-or-path>]`
16
+ - Mounts:
17
+ - `--auto-mount` (detect plugin/theme in CWD)
18
+ - `--mount=/abs/host:/vfs/path` (repeatable)
19
+ - `--mount-before-install` (apply mounts before WP install)
20
+
21
+ ### Run a blueprint
22
+
23
+ - `npx @wp-playground/cli@latest run-blueprint --blueprint=<file-or-url> [--blueprint-may-read-adjacent-files] [--wp=<ver>] [--php=<ver>] [--verbosity=debug]`
24
+ - Use for scripted setup; no persistent server.
25
+
26
+ ### Build a snapshot
27
+
28
+ - `npx @wp-playground/cli@latest build-snapshot --blueprint=<file-or-url> --outfile=./site.zip [--verbosity=debug]`
29
+ - Produces a sharable ZIP usable by Playground UI or other CLI commands.
30
+
31
+ ### Debugging flags
32
+
33
+ - `--xdebug` / `--enable-xdebug` (depends on release) to start Xdebug listener.
34
+ - `--experimental-multi-worker` to speed multi-step blueprints; disable if unstable.
35
+
36
+ ### Version control
37
+
38
+ - `--wp=<version>` to pick WordPress version (defaults to latest).
39
+ - `--php=<version>` to pick PHP version (defaults to 8.3 since July 2025).