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.
- package/.github/agents/wp-architect.agent.md +42 -0
- package/.github/copilot-instructions.md +2 -0
- package/.github/instructions/wordpress-workflow.instructions.md +41 -0
- package/.github/prompts/plan-smartDetectionSetup.prompt.md +189 -0
- package/.github/skills/wordpress-router/SKILL.md +51 -0
- package/.github/skills/wordpress-router/references/decision-tree.md +55 -0
- package/.github/skills/wp-abilities-api/SKILL.md +95 -0
- package/.github/skills/wp-abilities-api/references/php-registration.md +67 -0
- package/.github/skills/wp-abilities-api/references/rest-api.md +13 -0
- package/.github/skills/wp-block-development/SKILL.md +174 -0
- package/.github/skills/wp-block-development/references/attributes-and-serialization.md +22 -0
- package/.github/skills/wp-block-development/references/block-json.md +49 -0
- package/.github/skills/wp-block-development/references/creating-new-blocks.md +46 -0
- package/.github/skills/wp-block-development/references/debugging.md +36 -0
- package/.github/skills/wp-block-development/references/deprecations.md +24 -0
- package/.github/skills/wp-block-development/references/dynamic-rendering.md +23 -0
- package/.github/skills/wp-block-development/references/inner-blocks.md +25 -0
- package/.github/skills/wp-block-development/references/registration.md +30 -0
- package/.github/skills/wp-block-development/references/supports-and-wrappers.md +18 -0
- package/.github/skills/wp-block-development/references/tooling-and-testing.md +21 -0
- package/.github/skills/wp-block-development/scripts/list_blocks.mjs +121 -0
- package/.github/skills/wp-block-themes/SKILL.md +116 -0
- package/.github/skills/wp-block-themes/references/creating-new-block-theme.md +37 -0
- package/.github/skills/wp-block-themes/references/debugging.md +24 -0
- package/.github/skills/wp-block-themes/references/patterns.md +18 -0
- package/.github/skills/wp-block-themes/references/style-variations.md +14 -0
- package/.github/skills/wp-block-themes/references/templates-and-parts.md +16 -0
- package/.github/skills/wp-block-themes/references/theme-json.md +59 -0
- package/.github/skills/wp-block-themes/scripts/detect_block_themes.mjs +117 -0
- package/.github/skills/wp-interactivity-api/SKILL.md +179 -0
- package/.github/skills/wp-interactivity-api/references/debugging.md +29 -0
- package/.github/skills/wp-interactivity-api/references/directives-quickref.md +30 -0
- package/.github/skills/wp-interactivity-api/references/server-side-rendering.md +310 -0
- package/.github/skills/wp-performance/SKILL.md +146 -0
- package/.github/skills/wp-performance/references/autoload-options.md +24 -0
- package/.github/skills/wp-performance/references/cron.md +20 -0
- package/.github/skills/wp-performance/references/database.md +20 -0
- package/.github/skills/wp-performance/references/http-api.md +15 -0
- package/.github/skills/wp-performance/references/measurement.md +21 -0
- package/.github/skills/wp-performance/references/object-cache.md +24 -0
- package/.github/skills/wp-performance/references/query-monitor-headless.md +38 -0
- package/.github/skills/wp-performance/references/server-timing.md +22 -0
- package/.github/skills/wp-performance/references/wp-cli-doctor.md +24 -0
- package/.github/skills/wp-performance/references/wp-cli-profile.md +32 -0
- package/.github/skills/wp-performance/scripts/perf_inspect.mjs +128 -0
- package/.github/skills/wp-phpstan/SKILL.md +97 -0
- package/.github/skills/wp-phpstan/references/configuration.md +52 -0
- package/.github/skills/wp-phpstan/references/third-party-classes.md +76 -0
- package/.github/skills/wp-phpstan/references/wordpress-annotations.md +124 -0
- package/.github/skills/wp-phpstan/scripts/phpstan_inspect.mjs +263 -0
- package/.github/skills/wp-playground/SKILL.md +101 -0
- package/.github/skills/wp-playground/references/blueprints.md +36 -0
- package/.github/skills/wp-playground/references/cli-commands.md +39 -0
- package/.github/skills/wp-playground/references/debugging.md +16 -0
- package/.github/skills/wp-plugin-development/SKILL.md +112 -0
- package/.github/skills/wp-plugin-development/references/data-and-cron.md +19 -0
- package/.github/skills/wp-plugin-development/references/debugging.md +19 -0
- package/.github/skills/wp-plugin-development/references/lifecycle.md +33 -0
- package/.github/skills/wp-plugin-development/references/security.md +29 -0
- package/.github/skills/wp-plugin-development/references/settings-api.md +22 -0
- package/.github/skills/wp-plugin-development/references/structure.md +16 -0
- package/.github/skills/wp-plugin-development/scripts/detect_plugins.mjs +122 -0
- package/.github/skills/wp-project-triage/SKILL.md +38 -0
- package/.github/skills/wp-project-triage/references/triage.schema.json +143 -0
- package/.github/skills/wp-project-triage/scripts/detect_wp_project.mjs +592 -0
- package/.github/skills/wp-rest-api/SKILL.md +114 -0
- package/.github/skills/wp-rest-api/references/authentication.md +18 -0
- package/.github/skills/wp-rest-api/references/custom-content-types.md +20 -0
- package/.github/skills/wp-rest-api/references/discovery-and-params.md +20 -0
- package/.github/skills/wp-rest-api/references/responses-and-fields.md +30 -0
- package/.github/skills/wp-rest-api/references/routes-and-endpoints.md +36 -0
- package/.github/skills/wp-rest-api/references/schema.md +22 -0
- package/.github/skills/wp-wpcli-and-ops/SKILL.md +123 -0
- package/.github/skills/wp-wpcli-and-ops/references/automation.md +30 -0
- package/.github/skills/wp-wpcli-and-ops/references/cron-and-cache.md +23 -0
- package/.github/skills/wp-wpcli-and-ops/references/debugging.md +17 -0
- package/.github/skills/wp-wpcli-and-ops/references/multisite.md +22 -0
- package/.github/skills/wp-wpcli-and-ops/references/packages-and-updates.md +22 -0
- package/.github/skills/wp-wpcli-and-ops/references/safety.md +30 -0
- package/.github/skills/wp-wpcli-and-ops/references/search-replace.md +40 -0
- package/.github/skills/wp-wpcli-and-ops/scripts/wpcli_inspect.mjs +90 -0
- package/.github/skills/wpds/SKILL.md +58 -0
- package/AGENTS.md +39 -0
- package/AGENTS.template.md +31 -0
- package/LICENSE +342 -0
- package/README.md +118 -0
- package/dist/cli.js +19 -0
- package/dist/commands/install.js +27 -0
- package/dist/commands/run-playground.js +28 -0
- package/dist/commands/setup.js +237 -0
- package/dist/commands/sync-skills.js +70 -0
- package/dist/lib/installer.js +56 -0
- package/dist/lib/triage-mapper.js +98 -0
- package/dist/utils/paths.js +12 -0
- package/dist/utils/run.js +20 -0
- 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
|
+
}
|