wordpress-agent-kit 0.2.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 (96) hide show
  1. package/.github/agents/wp-architect.agent.md +42 -0
  2. package/.github/copilot-instructions.md +2 -0
  3. package/.github/instructions/wordpress-workflow.instructions.md +41 -0
  4. package/.github/prompts/plan-smartDetectionSetup.prompt.md +189 -0
  5. package/.github/skills/wordpress-router/SKILL.md +51 -0
  6. package/.github/skills/wordpress-router/references/decision-tree.md +55 -0
  7. package/.github/skills/wp-abilities-api/SKILL.md +95 -0
  8. package/.github/skills/wp-abilities-api/references/php-registration.md +67 -0
  9. package/.github/skills/wp-abilities-api/references/rest-api.md +13 -0
  10. package/.github/skills/wp-block-development/SKILL.md +174 -0
  11. package/.github/skills/wp-block-development/references/attributes-and-serialization.md +22 -0
  12. package/.github/skills/wp-block-development/references/block-json.md +49 -0
  13. package/.github/skills/wp-block-development/references/creating-new-blocks.md +46 -0
  14. package/.github/skills/wp-block-development/references/debugging.md +36 -0
  15. package/.github/skills/wp-block-development/references/deprecations.md +24 -0
  16. package/.github/skills/wp-block-development/references/dynamic-rendering.md +23 -0
  17. package/.github/skills/wp-block-development/references/inner-blocks.md +25 -0
  18. package/.github/skills/wp-block-development/references/registration.md +30 -0
  19. package/.github/skills/wp-block-development/references/supports-and-wrappers.md +18 -0
  20. package/.github/skills/wp-block-development/references/tooling-and-testing.md +21 -0
  21. package/.github/skills/wp-block-development/scripts/list_blocks.mjs +121 -0
  22. package/.github/skills/wp-block-themes/SKILL.md +116 -0
  23. package/.github/skills/wp-block-themes/references/creating-new-block-theme.md +37 -0
  24. package/.github/skills/wp-block-themes/references/debugging.md +24 -0
  25. package/.github/skills/wp-block-themes/references/patterns.md +18 -0
  26. package/.github/skills/wp-block-themes/references/style-variations.md +14 -0
  27. package/.github/skills/wp-block-themes/references/templates-and-parts.md +16 -0
  28. package/.github/skills/wp-block-themes/references/theme-json.md +59 -0
  29. package/.github/skills/wp-block-themes/scripts/detect_block_themes.mjs +117 -0
  30. package/.github/skills/wp-interactivity-api/SKILL.md +179 -0
  31. package/.github/skills/wp-interactivity-api/references/debugging.md +29 -0
  32. package/.github/skills/wp-interactivity-api/references/directives-quickref.md +30 -0
  33. package/.github/skills/wp-interactivity-api/references/server-side-rendering.md +310 -0
  34. package/.github/skills/wp-performance/SKILL.md +146 -0
  35. package/.github/skills/wp-performance/references/autoload-options.md +24 -0
  36. package/.github/skills/wp-performance/references/cron.md +20 -0
  37. package/.github/skills/wp-performance/references/database.md +20 -0
  38. package/.github/skills/wp-performance/references/http-api.md +15 -0
  39. package/.github/skills/wp-performance/references/measurement.md +21 -0
  40. package/.github/skills/wp-performance/references/object-cache.md +24 -0
  41. package/.github/skills/wp-performance/references/query-monitor-headless.md +38 -0
  42. package/.github/skills/wp-performance/references/server-timing.md +22 -0
  43. package/.github/skills/wp-performance/references/wp-cli-doctor.md +24 -0
  44. package/.github/skills/wp-performance/references/wp-cli-profile.md +32 -0
  45. package/.github/skills/wp-performance/scripts/perf_inspect.mjs +128 -0
  46. package/.github/skills/wp-phpstan/SKILL.md +97 -0
  47. package/.github/skills/wp-phpstan/references/configuration.md +52 -0
  48. package/.github/skills/wp-phpstan/references/third-party-classes.md +76 -0
  49. package/.github/skills/wp-phpstan/references/wordpress-annotations.md +124 -0
  50. package/.github/skills/wp-phpstan/scripts/phpstan_inspect.mjs +263 -0
  51. package/.github/skills/wp-playground/SKILL.md +101 -0
  52. package/.github/skills/wp-playground/references/blueprints.md +36 -0
  53. package/.github/skills/wp-playground/references/cli-commands.md +39 -0
  54. package/.github/skills/wp-playground/references/debugging.md +16 -0
  55. package/.github/skills/wp-plugin-development/SKILL.md +112 -0
  56. package/.github/skills/wp-plugin-development/references/data-and-cron.md +19 -0
  57. package/.github/skills/wp-plugin-development/references/debugging.md +19 -0
  58. package/.github/skills/wp-plugin-development/references/lifecycle.md +33 -0
  59. package/.github/skills/wp-plugin-development/references/security.md +29 -0
  60. package/.github/skills/wp-plugin-development/references/settings-api.md +22 -0
  61. package/.github/skills/wp-plugin-development/references/structure.md +16 -0
  62. package/.github/skills/wp-plugin-development/scripts/detect_plugins.mjs +122 -0
  63. package/.github/skills/wp-project-triage/SKILL.md +38 -0
  64. package/.github/skills/wp-project-triage/references/triage.schema.json +143 -0
  65. package/.github/skills/wp-project-triage/scripts/detect_wp_project.mjs +592 -0
  66. package/.github/skills/wp-rest-api/SKILL.md +114 -0
  67. package/.github/skills/wp-rest-api/references/authentication.md +18 -0
  68. package/.github/skills/wp-rest-api/references/custom-content-types.md +20 -0
  69. package/.github/skills/wp-rest-api/references/discovery-and-params.md +20 -0
  70. package/.github/skills/wp-rest-api/references/responses-and-fields.md +30 -0
  71. package/.github/skills/wp-rest-api/references/routes-and-endpoints.md +36 -0
  72. package/.github/skills/wp-rest-api/references/schema.md +22 -0
  73. package/.github/skills/wp-wpcli-and-ops/SKILL.md +123 -0
  74. package/.github/skills/wp-wpcli-and-ops/references/automation.md +30 -0
  75. package/.github/skills/wp-wpcli-and-ops/references/cron-and-cache.md +23 -0
  76. package/.github/skills/wp-wpcli-and-ops/references/debugging.md +17 -0
  77. package/.github/skills/wp-wpcli-and-ops/references/multisite.md +22 -0
  78. package/.github/skills/wp-wpcli-and-ops/references/packages-and-updates.md +22 -0
  79. package/.github/skills/wp-wpcli-and-ops/references/safety.md +30 -0
  80. package/.github/skills/wp-wpcli-and-ops/references/search-replace.md +40 -0
  81. package/.github/skills/wp-wpcli-and-ops/scripts/wpcli_inspect.mjs +90 -0
  82. package/.github/skills/wpds/SKILL.md +58 -0
  83. package/AGENTS.md +39 -0
  84. package/AGENTS.template.md +31 -0
  85. package/LICENSE +342 -0
  86. package/README.md +118 -0
  87. package/dist/cli.js +19 -0
  88. package/dist/commands/install.js +27 -0
  89. package/dist/commands/run-playground.js +28 -0
  90. package/dist/commands/setup.js +237 -0
  91. package/dist/commands/sync-skills.js +70 -0
  92. package/dist/lib/installer.js +56 -0
  93. package/dist/lib/triage-mapper.js +98 -0
  94. package/dist/utils/paths.js +12 -0
  95. package/dist/utils/run.js +20 -0
  96. package/package.json +55 -0
@@ -0,0 +1,237 @@
1
+ import { Command } from 'commander';
2
+ import * as p from '@clack/prompts';
3
+ import fs from 'node:fs';
4
+ import path from 'node:path';
5
+ import { spawnSync } from 'node:child_process';
6
+ import { PACKAGE_ROOT } from '../utils/paths.js';
7
+ import { installKit, PLATFORM_FOLDERS } from '../lib/installer.js';
8
+ import { mapProjectType, mapTechStack, hasConfidentDetection, formatDetectionResults } from '../lib/triage-mapper.js';
9
+ /**
10
+ * Command to interactively set up the WordPress Agent Kit.
11
+ * Handles detection of project type, installation, and configuration of AGENTS.md.
12
+ */
13
+ export const setupCommand = new Command('setup')
14
+ .description('Interactive setup for WordPress Agent Kit')
15
+ .argument('[dir]', 'Target directory', process.cwd())
16
+ .option('--reset', 'Reset and overwrite existing configuration')
17
+ .option('--platform <platform>', 'Target platform (github, cursor, claude, agent, pi)', 'github')
18
+ .action(async (dir, options) => {
19
+ const platform = options.platform;
20
+ const validPlatforms = ['github', 'cursor', 'claude', 'agent', 'pi'];
21
+ if (!validPlatforms.includes(platform)) {
22
+ console.error(`Invalid platform: ${platform}. Valid options: ${validPlatforms.join(', ')}`);
23
+ process.exit(1);
24
+ }
25
+ const platformFolder = PLATFORM_FOLDERS[platform];
26
+ console.clear();
27
+ p.intro('WordPress Agent Kit Setup');
28
+ const targetDir = path.resolve(dir);
29
+ // Check if target directory exists
30
+ if (!fs.existsSync(targetDir)) {
31
+ const shouldCreate = await p.confirm({
32
+ message: `Target directory doesn't exist: ${targetDir}\nCreate it?`,
33
+ initialValue: true,
34
+ });
35
+ if (p.isCancel(shouldCreate) || !shouldCreate) {
36
+ p.cancel('Setup cancelled.');
37
+ process.exit(0);
38
+ }
39
+ try {
40
+ fs.mkdirSync(targetDir, { recursive: true });
41
+ p.log.success(`Created directory: ${targetDir}`);
42
+ }
43
+ catch (err) {
44
+ p.log.error(`Failed to create directory: ${err.message}`);
45
+ process.exit(1);
46
+ }
47
+ }
48
+ p.log.info(`Setting up kit in: ${targetDir} (platform: ${platform})`);
49
+ // Check if kit is already installed
50
+ const agentsPath = path.join(targetDir, 'AGENTS.md');
51
+ const platformInstructionsPath = path.join(targetDir, platformFolder, 'instructions', 'wordpress-workflow.instructions.md');
52
+ if (options.reset && fs.existsSync(agentsPath)) {
53
+ const confirmReset = await p.confirm({
54
+ message: `Warning: --reset will overwrite existing AGENTS.md and ${platformFolder} configuration. Continue?`,
55
+ initialValue: false,
56
+ });
57
+ if (p.isCancel(confirmReset) || !confirmReset) {
58
+ p.cancel('Reset cancelled.');
59
+ process.exit(0);
60
+ }
61
+ // Force install if reset is confirmed
62
+ const s = p.spinner();
63
+ s.start('Re-installing kit files...');
64
+ try {
65
+ await installKit(targetDir, platform);
66
+ s.stop('Kit files reset.');
67
+ }
68
+ catch (err) {
69
+ s.stop('Reset failed.');
70
+ console.error(err.message);
71
+ process.exit(1);
72
+ }
73
+ }
74
+ else if (!fs.existsSync(agentsPath)) {
75
+ const shouldInstall = await p.confirm({
76
+ message: 'Kit not found in target repo. Install it first?',
77
+ initialValue: true,
78
+ });
79
+ if (p.isCancel(shouldInstall) || !shouldInstall) {
80
+ p.cancel('Setup cancelled.');
81
+ process.exit(0);
82
+ }
83
+ const s = p.spinner();
84
+ s.start('Installing kit files...');
85
+ try {
86
+ await installKit(targetDir, platform);
87
+ s.stop('Kit installed successfully.');
88
+ }
89
+ catch (err) {
90
+ s.stop('Installation failed.');
91
+ console.error(err.message);
92
+ process.exit(1);
93
+ }
94
+ }
95
+ // Run project triage BEFORE asking any questions
96
+ let triageResult = null;
97
+ let detectedType = null;
98
+ let detectedTech = [];
99
+ // Try to find triage script in multiple locations
100
+ const triageScriptPaths = [
101
+ path.join(targetDir, platformFolder, 'skills/wp-project-triage/scripts/detect_wp_project.mjs'),
102
+ path.join(process.cwd(), platformFolder, 'skills/wp-project-triage/scripts/detect_wp_project.mjs'),
103
+ path.resolve(PACKAGE_ROOT, 'vendor/wp-agent-skills/skills/wp-project-triage/scripts/detect_wp_project.mjs'),
104
+ ];
105
+ const triageScriptPath = triageScriptPaths.find(p => fs.existsSync(p));
106
+ if (triageScriptPath) {
107
+ const s = p.spinner();
108
+ s.start('Analyzing project structure...');
109
+ try {
110
+ const result = spawnSync('node', [triageScriptPath], {
111
+ cwd: targetDir,
112
+ encoding: 'utf-8',
113
+ });
114
+ if (result.status === 0 && result.stdout) {
115
+ triageResult = JSON.parse(result.stdout.trim());
116
+ detectedType = mapProjectType(triageResult.project?.primary);
117
+ detectedTech = mapTechStack(triageResult);
118
+ }
119
+ s.stop('Project analyzed.');
120
+ }
121
+ catch (err) {
122
+ s.stop('Auto-detection unavailable.');
123
+ p.log.warn('Could not run project triage. Proceeding with manual setup.');
124
+ }
125
+ }
126
+ else {
127
+ p.log.info('Project triage not available yet. Using manual setup.');
128
+ }
129
+ let detectedPackageManager = 'npm/pnpm';
130
+ if (triageResult && triageResult.tooling?.node?.packageManager) {
131
+ detectedPackageManager = triageResult.tooling.node.packageManager;
132
+ }
133
+ let useDetectedValues = false;
134
+ if (triageResult && hasConfidentDetection(detectedType, detectedTech)) {
135
+ p.note(formatDetectionResults(detectedType, detectedTech, triageResult), 'Auto-Detection Results');
136
+ const confirmDetection = await p.confirm({
137
+ message: 'Use these detected values?',
138
+ initialValue: true,
139
+ });
140
+ if (p.isCancel(confirmDetection)) {
141
+ p.cancel('Setup cancelled.');
142
+ process.exit(0);
143
+ }
144
+ useDetectedValues = confirmDetection;
145
+ }
146
+ else if (triageResult) {
147
+ if (detectedType || detectedTech.length > 0) {
148
+ p.note(formatDetectionResults(detectedType, detectedTech, triageResult), 'Partial Detection (will be used as defaults)');
149
+ }
150
+ }
151
+ let projectInfo;
152
+ if (useDetectedValues) {
153
+ projectInfo = {
154
+ projectType: detectedType,
155
+ techStack: detectedTech,
156
+ };
157
+ p.log.success('Using auto-detected configuration.');
158
+ }
159
+ else {
160
+ projectInfo = await p.group({
161
+ projectType: () => p.select({
162
+ message: 'What type of WordPress project is this?',
163
+ options: [
164
+ { value: 'plugin', label: 'Plugin' },
165
+ { value: 'theme', label: 'Theme' },
166
+ { value: 'block-theme', label: 'Block Theme' },
167
+ { value: 'site', label: 'Full Site / Multisite' },
168
+ { value: 'blocks', label: 'Gutenberg Blocks' },
169
+ { value: 'other', label: 'Other / Mixed' },
170
+ { value: 'unsure', label: "I'm not sure" },
171
+ ],
172
+ initialValue: detectedType || undefined,
173
+ }),
174
+ techStack: () => p.multiselect({
175
+ message: 'Select technologies (or skip if unsure):',
176
+ options: [
177
+ { value: 'gutenberg', label: 'Gutenberg Blocks', hint: 'block.json, @wordpress/blocks' },
178
+ { value: 'interactivity', label: 'Interactivity API', hint: 'data-wp-* directives' },
179
+ { value: 'rest-api', label: 'REST API', hint: 'Custom endpoints' },
180
+ { value: 'wpcli', label: 'WP-CLI', hint: 'Custom commands' },
181
+ { value: 'composer', label: 'Composer', hint: 'PHP dependencies' },
182
+ { value: 'npm', label: 'npm/pnpm', hint: 'JS build process' },
183
+ { value: 'phpstan', label: 'PHPStan', hint: 'Static analysis' },
184
+ { value: 'playground', label: 'WordPress Playground', hint: 'Testing/demo' },
185
+ ],
186
+ initialValues: detectedTech.length > 0 ? detectedTech : undefined,
187
+ required: false,
188
+ }),
189
+ }, {
190
+ onCancel: () => {
191
+ p.cancel('Setup cancelled.');
192
+ process.exit(0);
193
+ },
194
+ });
195
+ if (projectInfo.projectType === 'unsure') {
196
+ projectInfo.projectType = 'other';
197
+ p.log.info('Using "other" as project type. You can adjust AGENTS.md later.');
198
+ }
199
+ }
200
+ const customizeAgents = await p.confirm({
201
+ message: 'Customize AGENTS.md with project details?',
202
+ initialValue: true,
203
+ });
204
+ if (p.isCancel(customizeAgents)) {
205
+ p.cancel('Setup cancelled.');
206
+ process.exit(0);
207
+ }
208
+ if (customizeAgents) {
209
+ try {
210
+ let agentsContent = fs.readFileSync(agentsPath, 'utf-8');
211
+ agentsContent = agentsContent.replace(/\*\*Tooling\*\*: .*/, `**Tooling**: ${projectInfo.techStack.includes('composer') ? 'Composer for PHP' : ''}${projectInfo.techStack.includes('npm') ? `, ${detectedPackageManager} for JS` : ''}.`);
212
+ fs.writeFileSync(agentsPath, agentsContent, 'utf-8');
213
+ p.log.success('Updated AGENTS.md');
214
+ }
215
+ catch (err) {
216
+ p.log.warn(`Could not update AGENTS.md: ${err.message}`);
217
+ }
218
+ }
219
+ // Workflow instructions
220
+ if (fs.existsSync(platformInstructionsPath)) {
221
+ const customizeWorkflow = await p.confirm({
222
+ message: 'Open workflow instructions for manual editing?',
223
+ initialValue: false,
224
+ });
225
+ if (!p.isCancel(customizeWorkflow) && customizeWorkflow) {
226
+ p.note(`Edit: ${platformInstructionsPath}\n\nAdd your project-specific:\n- Coding standards\n- Git workflow\n- Testing procedures\n- Deployment steps`, 'Workflow Instructions');
227
+ }
228
+ }
229
+ const promptsFolder = path.join(targetDir, platformFolder, 'prompts');
230
+ p.note(`✓ Kit installed and configured\n\n` +
231
+ `Next steps:\n` +
232
+ `1. Review ${agentsPath}\n` +
233
+ `2. Customize ${promptsFolder}/ for your domain\n` +
234
+ `3. Test with: ${projectInfo.projectType === 'plugin' ? '"Create a new settings page"' : '"Generate a block variation"'}\n` +
235
+ `4. Adjust skills loading in AGENTS.md as needed`, 'Setup Complete');
236
+ p.outro('Your WordPress project is now AI-ready!');
237
+ });
@@ -0,0 +1,70 @@
1
+ import { Command } from 'commander';
2
+ import fs from 'node:fs';
3
+ import path from 'node:path';
4
+ import { run } from '../utils/run.js';
5
+ const OFFICIAL_SKILLS_REPO_URL = 'https://github.com/WordPress/agent-skills.git';
6
+ const DEFAULT_SKILLS_REF = 'trunk';
7
+ /**
8
+ * Command to sync skills from the official WordPress agent-skills repository.
9
+ * Can checkout a specific branch or tag.
10
+ */
11
+ export const syncSkillsCommand = new Command('sync-skills')
12
+ .description('Sync skills from the official WordPress agent-skills repository')
13
+ .argument('[ref]', 'Branch or tag to checkout', DEFAULT_SKILLS_REF)
14
+ .action((refPassed) => {
15
+ // Check for custom URL args - simplistic check
16
+ if (/^(https?:\/\/|git@)/i.test(refPassed)) {
17
+ console.error('Custom skills repository URLs are not supported. This script syncs from the official WordPress/agent-skills repo only.');
18
+ process.exit(2);
19
+ }
20
+ // Check if refPassed might contain URL (same check as above) or empty string
21
+ const ref = refPassed || DEFAULT_SKILLS_REF;
22
+ const repoRoot = process.cwd();
23
+ const submodulePath = path.join('vendor', 'wp-agent-skills');
24
+ const vendorSkillsDir = path.join(repoRoot, submodulePath);
25
+ const submoduleGitDir = path.join(vendorSkillsDir, '.git');
26
+ // Clone or update the skills repo (not as a submodule since it's gitignored)
27
+ if (!fs.existsSync(submoduleGitDir)) {
28
+ fs.mkdirSync(path.join(repoRoot, 'vendor'), { recursive: true });
29
+ console.log(`Cloning ${OFFICIAL_SKILLS_REPO_URL} into ${submodulePath}...`);
30
+ run('git', ['clone', OFFICIAL_SKILLS_REPO_URL, submodulePath], repoRoot);
31
+ }
32
+ else {
33
+ console.log(`Updating existing skills repo at ${submodulePath}...`);
34
+ run('git', ['fetch', '--all', '--tags'], vendorSkillsDir);
35
+ }
36
+ // Checkout the specified ref
37
+ if (ref) {
38
+ run('git', ['checkout', ref], vendorSkillsDir);
39
+ run('git', ['pull', 'origin', ref], vendorSkillsDir);
40
+ }
41
+ const targetSkills = path.join(repoRoot, '.github', 'skills');
42
+ const upstreamBuildScript = path.join(vendorSkillsDir, 'shared', 'scripts', 'skillpack-build.mjs');
43
+ const upstreamInstallScript = path.join(vendorSkillsDir, 'shared', 'scripts', 'skillpack-install.mjs');
44
+ if (fs.existsSync(upstreamBuildScript) && fs.existsSync(upstreamInstallScript)) {
45
+ if (fs.existsSync(targetSkills)) {
46
+ fs.rmSync(targetSkills, { recursive: true, force: true });
47
+ }
48
+ fs.mkdirSync(path.join(repoRoot, '.github'), { recursive: true });
49
+ run('node', ['shared/scripts/skillpack-build.mjs', '--clean', '--targets=vscode'], vendorSkillsDir);
50
+ run('node', ['shared/scripts/skillpack-install.mjs', `--dest=${repoRoot}`, '--targets=vscode', '--from=dist', '--mode=replace'], vendorSkillsDir);
51
+ console.log(`Synced skills into: ${targetSkills}`);
52
+ console.log(`Skills source: ${OFFICIAL_SKILLS_REPO_URL}${ref ? ` @ ${ref}` : ''}`);
53
+ console.log('Sync method: upstream skillpack-build.mjs + skillpack-install.mjs');
54
+ // No process.exit here, let commander handle exit or fallthrough unless explicit stop
55
+ return;
56
+ }
57
+ const sourceSkills = path.join(vendorSkillsDir, '.github', 'skills');
58
+ if (!fs.existsSync(sourceSkills)) {
59
+ console.error(`Could not find upstream skills directory at: ${sourceSkills}`);
60
+ process.exit(1);
61
+ }
62
+ if (fs.existsSync(targetSkills)) {
63
+ fs.rmSync(targetSkills, { recursive: true, force: true });
64
+ }
65
+ fs.mkdirSync(path.join(repoRoot, '.github'), { recursive: true });
66
+ fs.cpSync(sourceSkills, targetSkills, { recursive: true });
67
+ console.log(`Synced skills into: ${targetSkills}`);
68
+ console.log(`Skills source: ${OFFICIAL_SKILLS_REPO_URL}${ref ? ` @ ${ref}` : ''}`);
69
+ console.log('Sync method: fallback direct copy from .github/skills');
70
+ });
@@ -0,0 +1,56 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { PACKAGE_ROOT } from '../utils/paths.js';
4
+ /**
5
+ * Platform-specific folder names
6
+ */
7
+ export const PLATFORM_FOLDERS = {
8
+ github: '.github',
9
+ cursor: '.cursor',
10
+ claude: '.claude',
11
+ agent: '.agent',
12
+ pi: '.pi/agent',
13
+ };
14
+ /**
15
+ * Installs the WordPress Agent Kit into the specified directory for a given platform.
16
+ * Copies the platform-specific folder and AGENTS.md template.
17
+ *
18
+ * @param {string} targetDir - The directory where the kit should be installed.
19
+ * @param {Platform} platform - The target platform (github, cursor, claude, agent)
20
+ * @returns {Promise<void>}
21
+ */
22
+ export async function installKit(targetDir, platform = 'github') {
23
+ const platformFolder = PLATFORM_FOLDERS[platform];
24
+ console.log(`Installing WordPress Agent Kit (${platform}) into: ${targetDir}`);
25
+ if (!fs.existsSync(targetDir)) {
26
+ fs.mkdirSync(targetDir, { recursive: true });
27
+ }
28
+ const templatePath = path.join(PACKAGE_ROOT, 'AGENTS.template.md');
29
+ const agentsPath = path.join(PACKAGE_ROOT, 'AGENTS.md');
30
+ const sourceGithub = path.join(PACKAGE_ROOT, '.github');
31
+ // Copy platform-specific folder
32
+ const targetPlatform = path.join(targetDir, platformFolder);
33
+ if (fs.existsSync(targetPlatform)) {
34
+ fs.rmSync(targetPlatform, { recursive: true, force: true });
35
+ }
36
+ if (fs.existsSync(sourceGithub)) {
37
+ fs.cpSync(sourceGithub, targetPlatform, { recursive: true });
38
+ }
39
+ else {
40
+ throw new Error('Could not find source .github directory.');
41
+ }
42
+ // Copy AGENTS.md
43
+ const targetAgentsTemplate = path.join(targetDir, 'AGENTS.template.md');
44
+ if (fs.existsSync(templatePath)) {
45
+ fs.copyFileSync(templatePath, targetAgentsTemplate);
46
+ }
47
+ const targetAgents = path.join(targetDir, 'AGENTS.md');
48
+ if (!fs.existsSync(targetAgents)) {
49
+ if (fs.existsSync(templatePath)) {
50
+ fs.copyFileSync(templatePath, targetAgents);
51
+ }
52
+ else if (fs.existsSync(agentsPath)) {
53
+ fs.copyFileSync(agentsPath, targetAgents);
54
+ }
55
+ }
56
+ }
@@ -0,0 +1,98 @@
1
+ /**
2
+ * Maps triage detection results to setup configuration
3
+ */
4
+ /**
5
+ * Maps project.primary to setup's project type options
6
+ * @param {string} primary - The primary project type from triage
7
+ * @returns {string|null} - Mapped project type or null
8
+ */
9
+ export function mapProjectType(primary) {
10
+ const typeMap = {
11
+ 'wp-block-theme': 'block-theme',
12
+ 'wp-block-plugin': 'blocks',
13
+ 'wp-plugin': 'plugin',
14
+ 'wp-mu-plugin': 'plugin',
15
+ 'wp-theme': 'theme',
16
+ 'wp-site': 'site',
17
+ 'wp-core': 'other',
18
+ 'gutenberg': 'blocks',
19
+ 'unknown': null,
20
+ };
21
+ return typeMap[primary] || null;
22
+ }
23
+ /**
24
+ * Maps triage signals and tooling to tech stack array
25
+ * @param {object} triageResult - Full triage result object
26
+ * @returns {string[]} - Array of tech stack values
27
+ */
28
+ export function mapTechStack(triageResult) {
29
+ const techStack = [];
30
+ const { signals, tooling } = triageResult;
31
+ // Map signals
32
+ if (signals.blockJsonFiles && signals.blockJsonFiles.length > 0) {
33
+ techStack.push('gutenberg');
34
+ }
35
+ if (signals.usesInteractivityApi) {
36
+ techStack.push('interactivity');
37
+ }
38
+ if (signals.usesWpCli) {
39
+ techStack.push('wpcli');
40
+ }
41
+ if (signals.usesRestApi) {
42
+ techStack.push('rest-api');
43
+ }
44
+ // Map tooling
45
+ if (tooling.php?.hasComposerJson) {
46
+ techStack.push('composer');
47
+ }
48
+ if (tooling.php?.hasPhpStan) {
49
+ techStack.push('phpstan');
50
+ }
51
+ if (tooling.node?.hasPackageJson) {
52
+ techStack.push('npm');
53
+ }
54
+ // Check for playground blueprint
55
+ if (signals.hasPlaygroundBlueprint) {
56
+ techStack.push('playground');
57
+ }
58
+ return techStack;
59
+ }
60
+ /**
61
+ * Checks if detection has enough confidence to skip questions
62
+ * @param {string|null} detectedType - Detected project type
63
+ * @param {string[]} detectedTech - Detected tech stack
64
+ * @returns {boolean} - True if confident enough
65
+ */
66
+ export function hasConfidentDetection(detectedType, detectedTech) {
67
+ return detectedType !== null && detectedType !== 'other';
68
+ }
69
+ /**
70
+ * Formats detection results for display
71
+ * @param {string|null} detectedType - Detected project type
72
+ * @param {string[]} detectedTech - Detected tech stack
73
+ * @param {object} triageResult - Full triage result for additional notes
74
+ * @returns {string} - Formatted string for display
75
+ */
76
+ export function formatDetectionResults(detectedType, detectedTech, triageResult) {
77
+ const typeLabels = {
78
+ 'plugin': 'WordPress Plugin',
79
+ 'theme': 'WordPress Theme',
80
+ 'block-theme': 'Block Theme',
81
+ 'site': 'Full Site / Multisite',
82
+ 'blocks': 'Gutenberg Blocks',
83
+ 'other': 'Other / Mixed',
84
+ };
85
+ const techLabels = {
86
+ 'gutenberg': 'Blocks',
87
+ 'interactivity': 'Interactivity API',
88
+ 'wpcli': 'WP-CLI',
89
+ 'rest-api': 'REST API',
90
+ 'composer': 'Composer',
91
+ 'phpstan': 'PHPStan',
92
+ 'npm': 'npm/package.json',
93
+ 'playground': 'Playground',
94
+ };
95
+ const typeLabel = detectedType ? typeLabels[detectedType] : 'Unknown';
96
+ const techList = detectedTech.map(t => techLabels[t] || t).join(', ');
97
+ return `Project Type: ${typeLabel}\nTech Stack: ${techList}`;
98
+ }
@@ -0,0 +1,12 @@
1
+ import { fileURLToPath } from 'node:url';
2
+ import path from 'node:path';
3
+ // Get the root directory of the package (where package.json lives)
4
+ // When running from src (ts-node), it's ../
5
+ // When running from dist (node), it's ../
6
+ const __filename = fileURLToPath(import.meta.url);
7
+ const __dirname = path.dirname(__filename);
8
+ /**
9
+ * The absolute path to the root directory of the package.
10
+ * Resolves to the directory containing package.json.
11
+ */
12
+ export const PACKAGE_ROOT = path.resolve(__dirname, '../../');
@@ -0,0 +1,20 @@
1
+ import { spawnSync } from 'node:child_process';
2
+ /**
3
+ * Executes a shell command synchronously and exits the process if it fails.
4
+ *
5
+ * @param {string} command - The command to execute (e.g., 'npm', 'git').
6
+ * @param {string[]} args - An array of arguments for the command.
7
+ * @param {string} [cwd] - The current working directory for the command. Defaults to process.cwd().
8
+ * @returns {void}
9
+ */
10
+ export function run(command, args, cwd = process.cwd()) {
11
+ const result = spawnSync(command, args, {
12
+ cwd,
13
+ stdio: 'inherit',
14
+ shell: process.platform === 'win32'
15
+ });
16
+ if (result.status !== 0) {
17
+ console.error(`Command failed with status ${result.status}: ${command} ${args.join(' ')}`);
18
+ process.exit(result.status || 1);
19
+ }
20
+ }
package/package.json ADDED
@@ -0,0 +1,55 @@
1
+ {
2
+ "name": "wordpress-agent-kit",
3
+ "version": "0.2.1",
4
+ "description": "WordPress-focused AGENTS.md + Agent Skills starter kit for AI coding agents.",
5
+ "license": "GPL-2.0-or-later",
6
+ "author": "Kyle Brodeur <kyle@brodeur.me> (https://brodeur.me)",
7
+ "homepage": "https://brodeur.me",
8
+ "private": false,
9
+ "type": "module",
10
+ "keywords": [
11
+ "wordpress",
12
+ "agents",
13
+ "agents-md",
14
+ "agent-skills",
15
+ "ai-coding",
16
+ "copilot"
17
+ ],
18
+ "engines": {
19
+ "node": ">=20.18"
20
+ },
21
+ "bin": {
22
+ "wp-agent-kit": "dist/cli.js"
23
+ },
24
+ "dependencies": {
25
+ "@clack/prompts": "^0.8.2",
26
+ "commander": "^13.0.0"
27
+ },
28
+ "devDependencies": {
29
+ "@eslint/js": "^9.17.0",
30
+ "@types/node": "^22.10.1",
31
+ "@vitest/coverage-v8": "^2.1.8",
32
+ "eslint": "^9.16.0",
33
+ "prettier": "^3.4.1",
34
+ "ts-node": "^10.9.2",
35
+ "tsx": "^4.19.2",
36
+ "typescript": "^5.7.2",
37
+ "typescript-eslint": "^8.18.0",
38
+ "vitest": "^2.1.8",
39
+ "@earendil-works/pi-coding-agent": "^0.78.1"
40
+ },
41
+ "scripts": {
42
+ "dev": "tsx src/cli.ts",
43
+ "build": "tsc",
44
+ "check": "tsc --noEmit",
45
+ "lint": "eslint src/ --fix",
46
+ "test": "vitest",
47
+ "test:run": "vitest run",
48
+ "test:coverage": "vitest run --coverage",
49
+ "install:kit": "tsx src/cli.ts install",
50
+ "sync:skills": "tsx src/cli.ts sync-skills",
51
+ "setup": "tsx src/cli.ts setup",
52
+ "playground": "tsx src/cli.ts playground",
53
+ "build:bundles": "tsx scripts/build-bundles.ts"
54
+ }
55
+ }