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.
- package/.agents/skills/blueprint/SKILL.md +418 -0
- package/.agents/skills/wordpress-router/SKILL.md +52 -0
- package/.agents/skills/wordpress-router/references/decision-tree.md +55 -0
- package/.agents/skills/wp-abilities-api/SKILL.md +108 -0
- package/.agents/skills/wp-abilities-api/references/delegate-helper-pattern.md +241 -0
- package/.agents/skills/wp-abilities-api/references/domain-vs-projection.md +113 -0
- package/.agents/skills/wp-abilities-api/references/error-code-vocabulary.md +123 -0
- package/.agents/skills/wp-abilities-api/references/grouping-heuristic.md +89 -0
- package/.agents/skills/wp-abilities-api/references/input-schema-gotchas.md +265 -0
- package/.agents/skills/wp-abilities-api/references/php-registration.md +94 -0
- package/.agents/skills/wp-abilities-api/references/plugin-family-patterns.md +233 -0
- package/.agents/skills/wp-abilities-api/references/rest-api.md +13 -0
- package/.agents/skills/wp-abilities-api/references/shared-core-service.md +184 -0
- package/.agents/skills/wp-abilities-audit/SKILL.md +199 -0
- package/.agents/skills/wp-abilities-audit/references/audit-schema.md +300 -0
- package/.agents/skills/wp-abilities-audit/references/capability-gate-tracing.md +197 -0
- package/.agents/skills/wp-abilities-audit/references/controller-enumeration.md +116 -0
- package/.agents/skills/wp-abilities-verify/SKILL.md +215 -0
- package/.agents/skills/wp-abilities-verify/references/annotation-correctness.md +154 -0
- package/.agents/skills/wp-abilities-verify/references/audit-schema-validation.md +131 -0
- package/.agents/skills/wp-abilities-verify/references/permission-roundtrip.md +190 -0
- package/.agents/skills/wp-abilities-verify/references/runtime-harness.md +462 -0
- package/.agents/skills/wp-abilities-verify/references/schema-lints.md +118 -0
- package/.agents/skills/wp-abilities-verify/references/static-enumeration.md +126 -0
- package/.agents/skills/wp-block-development/SKILL.md +175 -0
- package/.agents/skills/wp-block-development/references/attributes-and-serialization.md +22 -0
- package/.agents/skills/wp-block-development/references/block-json.md +49 -0
- package/.agents/skills/wp-block-development/references/creating-new-blocks.md +46 -0
- package/.agents/skills/wp-block-development/references/debugging.md +36 -0
- package/.agents/skills/wp-block-development/references/deprecations.md +24 -0
- package/.agents/skills/wp-block-development/references/dynamic-rendering.md +23 -0
- package/.agents/skills/wp-block-development/references/inner-blocks.md +25 -0
- package/.agents/skills/wp-block-development/references/registration.md +30 -0
- package/.agents/skills/wp-block-development/references/supports-and-wrappers.md +18 -0
- package/.agents/skills/wp-block-development/references/tooling-and-testing.md +21 -0
- package/.agents/skills/wp-block-development/scripts/list_blocks.mjs +121 -0
- package/.agents/skills/wp-block-themes/SKILL.md +117 -0
- package/.agents/skills/wp-block-themes/references/creating-new-block-theme.md +37 -0
- package/.agents/skills/wp-block-themes/references/debugging.md +24 -0
- package/.agents/skills/wp-block-themes/references/patterns.md +18 -0
- package/.agents/skills/wp-block-themes/references/style-variations.md +14 -0
- package/.agents/skills/wp-block-themes/references/templates-and-parts.md +16 -0
- package/.agents/skills/wp-block-themes/references/theme-json.md +59 -0
- package/.agents/skills/wp-block-themes/scripts/detect_block_themes.mjs +117 -0
- package/.agents/skills/wp-interactivity-api/SKILL.md +180 -0
- package/.agents/skills/wp-interactivity-api/references/debugging.md +29 -0
- package/.agents/skills/wp-interactivity-api/references/directives-quickref.md +30 -0
- package/.agents/skills/wp-interactivity-api/references/server-side-rendering.md +310 -0
- package/.agents/skills/wp-performance/SKILL.md +147 -0
- package/.agents/skills/wp-performance/references/autoload-options.md +24 -0
- package/.agents/skills/wp-performance/references/cron.md +20 -0
- package/.agents/skills/wp-performance/references/database.md +20 -0
- package/.agents/skills/wp-performance/references/http-api.md +15 -0
- package/.agents/skills/wp-performance/references/measurement.md +21 -0
- package/.agents/skills/wp-performance/references/object-cache.md +24 -0
- package/.agents/skills/wp-performance/references/query-monitor-headless.md +38 -0
- package/.agents/skills/wp-performance/references/server-timing.md +22 -0
- package/.agents/skills/wp-performance/references/wp-cli-doctor.md +24 -0
- package/.agents/skills/wp-performance/references/wp-cli-profile.md +32 -0
- package/.agents/skills/wp-performance/scripts/perf_inspect.mjs +128 -0
- package/.agents/skills/wp-phpstan/SKILL.md +98 -0
- package/.agents/skills/wp-phpstan/references/configuration.md +52 -0
- package/.agents/skills/wp-phpstan/references/third-party-classes.md +76 -0
- package/.agents/skills/wp-phpstan/references/wordpress-annotations.md +124 -0
- package/.agents/skills/wp-phpstan/scripts/phpstan_inspect.mjs +263 -0
- package/.agents/skills/wp-playground/SKILL.md +233 -0
- package/.agents/skills/wp-playground/references/blueprints.md +36 -0
- package/.agents/skills/wp-playground/references/cli-commands.md +39 -0
- package/.agents/skills/wp-playground/references/debugging.md +16 -0
- package/.agents/skills/wp-playground/references/e2e-playwright.md +115 -0
- package/.agents/skills/wp-plugin-development/SKILL.md +113 -0
- package/.agents/skills/wp-plugin-development/references/data-and-cron.md +19 -0
- package/.agents/skills/wp-plugin-development/references/debugging.md +19 -0
- package/.agents/skills/wp-plugin-development/references/lifecycle.md +33 -0
- package/.agents/skills/wp-plugin-development/references/security.md +29 -0
- package/.agents/skills/wp-plugin-development/references/settings-api.md +22 -0
- package/.agents/skills/wp-plugin-development/references/structure.md +16 -0
- package/.agents/skills/wp-plugin-development/scripts/detect_plugins.mjs +122 -0
- package/.agents/skills/wp-plugin-directory-guidelines/SKILL.md +133 -0
- package/.agents/skills/wp-plugin-directory-guidelines/references/gpl-compliance.md +217 -0
- package/.agents/skills/wp-plugin-directory-guidelines/references/guideline-review-checklist.md +592 -0
- package/.agents/skills/wp-plugin-directory-guidelines/references/naming-rules.md +121 -0
- package/.agents/skills/wp-project-triage/SKILL.md +39 -0
- package/.agents/skills/wp-project-triage/references/triage.schema.json +143 -0
- package/.agents/skills/wp-project-triage/scripts/detect_wp_project.mjs +610 -0
- package/.agents/skills/wp-rest-api/SKILL.md +115 -0
- package/.agents/skills/wp-rest-api/references/authentication.md +18 -0
- package/.agents/skills/wp-rest-api/references/custom-content-types.md +20 -0
- package/.agents/skills/wp-rest-api/references/discovery-and-params.md +20 -0
- package/.agents/skills/wp-rest-api/references/responses-and-fields.md +30 -0
- package/.agents/skills/wp-rest-api/references/routes-and-endpoints.md +36 -0
- package/.agents/skills/wp-rest-api/references/schema.md +22 -0
- package/.agents/skills/wp-wpcli-and-ops/SKILL.md +126 -0
- package/.agents/skills/wp-wpcli-and-ops/references/automation.md +30 -0
- package/.agents/skills/wp-wpcli-and-ops/references/cron-and-cache.md +23 -0
- package/.agents/skills/wp-wpcli-and-ops/references/debugging.md +17 -0
- package/.agents/skills/wp-wpcli-and-ops/references/multisite.md +22 -0
- package/.agents/skills/wp-wpcli-and-ops/references/packages-and-updates.md +22 -0
- package/.agents/skills/wp-wpcli-and-ops/references/safety.md +30 -0
- package/.agents/skills/wp-wpcli-and-ops/references/search-replace.md +40 -0
- package/.agents/skills/wp-wpcli-and-ops/scripts/wpcli_inspect.mjs +90 -0
- package/.agents/skills/wp-wpengine/SKILL.md +398 -0
- package/.agents/skills/wp-wpengine/references/ci-gate.md +469 -0
- package/.agents/skills/wp-wpengine/references/github-actions-deploy.md +736 -0
- package/.agents/skills/wp-wpengine/scripts/ci-gate.sh +118 -0
- package/.agents/skills/wp-wpengine/scripts/wpe-check.sh +89 -0
- package/.agents/skills/wp-wpengine/scripts/wpe-preflight.sh +104 -0
- package/.agents/skills/wpds/SKILL.md +59 -0
- package/.github/agents/wp-architect.agent.md +1 -2
- package/.github/copilot-instructions.md +1 -1
- package/.github/instructions/wordpress-workflow.instructions.md +3 -3
- package/.github/skills/wp-playground/SKILL.md +132 -1
- package/.github/skills/wp-playground/references/e2e-playwright.md +115 -0
- package/.github/skills/wp-wpengine/SKILL.md +127 -0
- package/AGENTS.md +22 -10
- package/AGENTS.template.md +20 -10
- package/README.md +93 -86
- package/dist/cli.js +5 -1
- package/dist/commands/clean-skills.js +64 -0
- package/dist/commands/setup.js +6 -2
- package/dist/commands/sync-skills.js +3 -0
- package/dist/lib/api.js +176 -4
- package/dist/lib/installer.js +166 -2
- package/extensions/wp-agent-kit/index.ts +185 -10
- package/package.json +10 -14
- package/skills-custom/wp-wpengine/SKILL.md +398 -0
- package/skills-custom/wp-wpengine/references/ci-gate.md +469 -0
- package/skills-custom/wp-wpengine/references/github-actions-deploy.md +736 -0
- package/skills-custom/wp-wpengine/scripts/ci-gate.sh +118 -0
- package/skills-custom/wp-wpengine/scripts/wpe-check.sh +89 -0
- package/skills-custom/wp-wpengine/scripts/wpe-preflight.sh +104 -0
- package/.github/workflows/ci.yml +0 -44
- package/.husky/pre-commit +0 -7
- package/CLI_REVIEW.md +0 -250
- package/biome.json +0 -39
package/dist/commands/setup.js
CHANGED
|
@@ -111,8 +111,12 @@ export const setupCommand = new Command('setup')
|
|
|
111
111
|
let detectedTech = [];
|
|
112
112
|
let detectedPackageManager = 'npm/pnpm';
|
|
113
113
|
const triageScriptPaths = [
|
|
114
|
+
// Canonical location (AgentSkills.io convention)
|
|
115
|
+
path.join(targetDir, '.agents', 'skills/wp-project-triage/scripts/detect_wp_project.mjs'),
|
|
116
|
+
// Legacy platform-specific location
|
|
114
117
|
path.join(targetDir, platformFolder, 'skills/wp-project-triage/scripts/detect_wp_project.mjs'),
|
|
115
|
-
|
|
118
|
+
// Source repo
|
|
119
|
+
path.join(PACKAGE_ROOT, '.agents', 'skills/wp-project-triage/scripts/detect_wp_project.mjs'),
|
|
116
120
|
];
|
|
117
121
|
const triageScriptPath = triageScriptPaths.find((p) => fs.existsSync(p));
|
|
118
122
|
if (triageScriptPath) {
|
|
@@ -291,6 +295,6 @@ export const setupCommand = new Command('setup')
|
|
|
291
295
|
console.log('\nNext steps:');
|
|
292
296
|
console.log(` 1. Review ${path.join(targetDir, 'AGENTS.md')}`);
|
|
293
297
|
console.log(` 2. Customize ${path.join(targetDir, platformFolder, 'prompts/')}`);
|
|
294
|
-
console.log(` 3. Run triage: node ${path.join(targetDir,
|
|
298
|
+
console.log(` 3. Run triage: node ${path.join(targetDir, '.agents', 'skills/wp-project-triage/scripts/detect_wp_project.mjs')}`);
|
|
295
299
|
process.exit(0);
|
|
296
300
|
});
|
|
@@ -30,6 +30,9 @@ export const syncSkillsCommand = new Command('sync-skills')
|
|
|
30
30
|
const data = result.data;
|
|
31
31
|
console.log(`✓ Synced ${data.skillsSynced} skills from WordPress/agent-skills@${ref}`);
|
|
32
32
|
console.log(` Method: ${data.method}`);
|
|
33
|
+
if (data.customMerged > 0) {
|
|
34
|
+
console.log(` Custom skills merged: ${data.customMerged}`);
|
|
35
|
+
}
|
|
33
36
|
console.log(` Duration: ${data.durationMs}ms`);
|
|
34
37
|
}
|
|
35
38
|
else if (isDryRunResult(result)) {
|
package/dist/lib/api.js
CHANGED
|
@@ -264,11 +264,38 @@ export async function syncSkillsApi(options = {}) {
|
|
|
264
264
|
fs.cpSync(sourceSkills, targetSkills, { recursive: true });
|
|
265
265
|
skillsSynced = fs.readdirSync(targetSkills).length;
|
|
266
266
|
}
|
|
267
|
-
|
|
267
|
+
// Merge custom skills (skills-custom/) — these are not part of the upstream
|
|
268
|
+
// WordPress/agent-skills repo and survive upstream syncs.
|
|
269
|
+
const customSkillsDir = path.join(PACKAGE_ROOT, 'skills-custom');
|
|
270
|
+
let customMerged = 0;
|
|
271
|
+
if (fs.existsSync(customSkillsDir)) {
|
|
272
|
+
for (const skillName of fs.readdirSync(customSkillsDir)) {
|
|
273
|
+
const src = path.join(customSkillsDir, skillName);
|
|
274
|
+
const dest = path.join(targetSkills, skillName);
|
|
275
|
+
if (fs.statSync(src).isDirectory()) {
|
|
276
|
+
const isNew = !fs.existsSync(dest);
|
|
277
|
+
fs.cpSync(src, dest, { recursive: true });
|
|
278
|
+
if (isNew) {
|
|
279
|
+
skillsSynced++;
|
|
280
|
+
}
|
|
281
|
+
customMerged++;
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
// Copy synced skills to the canonical .agents/skills/ directory
|
|
286
|
+
// (AgentSkills.io convention — the pi.skills path in package.json points here).
|
|
287
|
+
const canonicalSkills = path.join(PACKAGE_ROOT, '.agents', 'skills');
|
|
288
|
+
if (fs.existsSync(canonicalSkills)) {
|
|
289
|
+
fs.rmSync(canonicalSkills, { recursive: true, force: true });
|
|
290
|
+
}
|
|
291
|
+
fs.mkdirSync(path.join(PACKAGE_ROOT, '.agents'), { recursive: true });
|
|
292
|
+
fs.cpSync(targetSkills, canonicalSkills, { recursive: true });
|
|
293
|
+
return { success: true, skillsSynced, customMerged, method };
|
|
268
294
|
});
|
|
269
295
|
return formatter.success({
|
|
270
296
|
targetDir,
|
|
271
297
|
skillsSynced: result.skillsSynced,
|
|
298
|
+
customMerged: result.customMerged,
|
|
272
299
|
sourceUrl: 'https://github.com/WordPress/agent-skills.git',
|
|
273
300
|
ref,
|
|
274
301
|
durationMs: Date.now() - startTime,
|
|
@@ -321,7 +348,13 @@ function dryRunSyncSkills(targetDir, ref) {
|
|
|
321
348
|
actions.push({
|
|
322
349
|
type: 'create',
|
|
323
350
|
target: targetSkills,
|
|
324
|
-
description: 'Install synced skills',
|
|
351
|
+
description: 'Install synced skills to .github/skills (sync buffer), then copy to .agents/skills (canonical)',
|
|
352
|
+
});
|
|
353
|
+
const canonicalSkills = path.join(targetDir, '.agents', 'skills');
|
|
354
|
+
actions.push({
|
|
355
|
+
type: 'create',
|
|
356
|
+
target: canonicalSkills,
|
|
357
|
+
description: 'Copy synced skills to .agents/skills (canonical, AgentSkills.io convention)',
|
|
325
358
|
});
|
|
326
359
|
return new OutputFormatter('json', 'sync-skills', '0.0.0').success({
|
|
327
360
|
wouldExecute: true,
|
|
@@ -329,6 +362,7 @@ function dryRunSyncSkills(targetDir, ref) {
|
|
|
329
362
|
summary: {
|
|
330
363
|
targetDir,
|
|
331
364
|
skillsSynced: 0,
|
|
365
|
+
customMerged: 0,
|
|
332
366
|
sourceUrl: 'https://github.com/WordPress/agent-skills.git',
|
|
333
367
|
ref,
|
|
334
368
|
durationMs: 0,
|
|
@@ -343,9 +377,13 @@ export async function runTriageApi(options) {
|
|
|
343
377
|
const formatter = new OutputFormatter('json', 'triage', '0.0.0');
|
|
344
378
|
const { targetDir, platform = 'github' } = options;
|
|
345
379
|
try {
|
|
346
|
-
const platformFolder = getPlatformFolder(platform);
|
|
347
380
|
const triageScriptPaths = [
|
|
348
|
-
|
|
381
|
+
// Canonical location (AgentSkills.io convention)
|
|
382
|
+
path.join(targetDir, '.agents', 'skills/wp-project-triage/scripts/detect_wp_project.mjs'),
|
|
383
|
+
// Legacy platform-specific location
|
|
384
|
+
path.join(targetDir, getPlatformFolder(platform), 'skills/wp-project-triage/scripts/detect_wp_project.mjs'),
|
|
385
|
+
// Source repo
|
|
386
|
+
path.join(PACKAGE_ROOT, '.agents', 'skills/wp-project-triage/scripts/detect_wp_project.mjs'),
|
|
349
387
|
path.join(PACKAGE_ROOT, 'vendor/wp-agent-skills/skills/wp-project-triage/scripts/detect_wp_project.mjs'),
|
|
350
388
|
];
|
|
351
389
|
const triageScriptPath = triageScriptPaths.find((p) => fs.existsSync(p));
|
|
@@ -517,6 +555,140 @@ function getInstalledSummary(targetDir, platform) {
|
|
|
517
555
|
}
|
|
518
556
|
return summary;
|
|
519
557
|
}
|
|
558
|
+
/**
|
|
559
|
+
* Detect and optionally remove orphaned skills from a target installation.
|
|
560
|
+
* Compares the skills in the target platform directory against the source kit
|
|
561
|
+
* (upstream .agents/skills + skills-custom/) and identifies skills that exist
|
|
562
|
+
* in the target but not in the source.
|
|
563
|
+
*/
|
|
564
|
+
export async function cleanSkillsApi(options) {
|
|
565
|
+
const startTime = Date.now();
|
|
566
|
+
const formatter = new OutputFormatter('json', 'clean-skills', '0.0.0');
|
|
567
|
+
const { targetDir, platform, dryRun = false, remove = false } = options;
|
|
568
|
+
try {
|
|
569
|
+
// Canonical skills come from .agents/skills/ (AgentSkills.io convention)
|
|
570
|
+
// with skills-custom/ as supplemental source for custom skills.
|
|
571
|
+
const canonicalSkillsDir = path.join(PACKAGE_ROOT, '.agents', 'skills');
|
|
572
|
+
const customSkillsDir = path.join(PACKAGE_ROOT, 'skills-custom');
|
|
573
|
+
const targetSkillsDir = path.join(targetDir, '.agents', 'skills');
|
|
574
|
+
// Build set of canonical skill names (upstream + custom)
|
|
575
|
+
const canonicalSkills = new Set();
|
|
576
|
+
if (fs.existsSync(canonicalSkillsDir)) {
|
|
577
|
+
for (const entry of fs.readdirSync(canonicalSkillsDir)) {
|
|
578
|
+
const entryPath = path.join(canonicalSkillsDir, entry);
|
|
579
|
+
if (fs.statSync(entryPath).isDirectory()) {
|
|
580
|
+
canonicalSkills.add(entry);
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
if (fs.existsSync(customSkillsDir)) {
|
|
585
|
+
for (const entry of fs.readdirSync(customSkillsDir)) {
|
|
586
|
+
const entryPath = path.join(customSkillsDir, entry);
|
|
587
|
+
if (fs.statSync(entryPath).isDirectory()) {
|
|
588
|
+
canonicalSkills.add(entry);
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
// Find orphaned skills in target .agents/skills/
|
|
593
|
+
const orphanedSkills = [];
|
|
594
|
+
if (fs.existsSync(targetSkillsDir)) {
|
|
595
|
+
for (const entry of fs.readdirSync(targetSkillsDir)) {
|
|
596
|
+
const entryPath = path.join(targetSkillsDir, entry);
|
|
597
|
+
if (fs.statSync(entryPath).isDirectory() && !canonicalSkills.has(entry)) {
|
|
598
|
+
orphanedSkills.push(entry);
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
// Detect legacy skill directories (platform-specific skills/ dirs)
|
|
603
|
+
const platformFolder = getPlatformFolder(platform);
|
|
604
|
+
const legacySkillsDir = path.join(targetDir, platformFolder, 'skills');
|
|
605
|
+
const legacySkillDirs = [];
|
|
606
|
+
if (fs.existsSync(legacySkillsDir)) {
|
|
607
|
+
legacySkillDirs.push(legacySkillsDir);
|
|
608
|
+
}
|
|
609
|
+
// Also check .github/skills for github platform (common legacy location)
|
|
610
|
+
if (platform !== 'github') {
|
|
611
|
+
const githubSkills = path.join(targetDir, '.github', 'skills');
|
|
612
|
+
if (fs.existsSync(githubSkills)) {
|
|
613
|
+
legacySkillDirs.push(githubSkills);
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
// Migrate legacy skills to .agents/skills/ and remove legacy dirs
|
|
617
|
+
const migratedSkills = [];
|
|
618
|
+
if (remove && !dryRun && legacySkillDirs.length > 0) {
|
|
619
|
+
for (const legacyDir of legacySkillDirs) {
|
|
620
|
+
for (const entry of fs.readdirSync(legacyDir)) {
|
|
621
|
+
const entryPath = path.join(legacyDir, entry);
|
|
622
|
+
if (!fs.statSync(entryPath).isDirectory())
|
|
623
|
+
continue;
|
|
624
|
+
const destPath = path.join(targetSkillsDir, entry);
|
|
625
|
+
if (!fs.existsSync(destPath)) {
|
|
626
|
+
fs.mkdirSync(path.dirname(destPath), { recursive: true });
|
|
627
|
+
fs.cpSync(entryPath, destPath, { recursive: true });
|
|
628
|
+
migratedSkills.push(entry);
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
// Remove the legacy skills directory
|
|
632
|
+
fs.rmSync(legacyDir, { recursive: true, force: true });
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
// Remove orphans if requested
|
|
636
|
+
const removedSkills = [];
|
|
637
|
+
if (remove && !dryRun) {
|
|
638
|
+
for (const orphan of orphanedSkills) {
|
|
639
|
+
const orphanPath = path.join(targetSkillsDir, orphan);
|
|
640
|
+
fs.rmSync(orphanPath, { recursive: true, force: true });
|
|
641
|
+
removedSkills.push(orphan);
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
const _durationMs = Date.now() - startTime;
|
|
645
|
+
if (dryRun) {
|
|
646
|
+
const actions = orphanedSkills.map((s) => ({
|
|
647
|
+
type: 'delete',
|
|
648
|
+
target: path.join('.agents', 'skills', s),
|
|
649
|
+
description: `Remove orphaned skill: ${s}`,
|
|
650
|
+
}));
|
|
651
|
+
for (const legacyDir of legacySkillDirs) {
|
|
652
|
+
actions.push({
|
|
653
|
+
type: 'delete',
|
|
654
|
+
target: legacyDir,
|
|
655
|
+
description: `Migrate and remove legacy skill directory: ${path.relative(targetDir, legacyDir)}`,
|
|
656
|
+
});
|
|
657
|
+
}
|
|
658
|
+
return formatter.success({
|
|
659
|
+
wouldExecute: true,
|
|
660
|
+
actions,
|
|
661
|
+
summary: {
|
|
662
|
+
targetDir,
|
|
663
|
+
platform,
|
|
664
|
+
orphanedSkills,
|
|
665
|
+
removedSkills: [],
|
|
666
|
+
legacySkillDirs,
|
|
667
|
+
migratedSkills: [],
|
|
668
|
+
dryRun: true,
|
|
669
|
+
},
|
|
670
|
+
});
|
|
671
|
+
}
|
|
672
|
+
return formatter.success({
|
|
673
|
+
targetDir,
|
|
674
|
+
platform,
|
|
675
|
+
orphanedSkills,
|
|
676
|
+
removedSkills,
|
|
677
|
+
legacySkillDirs,
|
|
678
|
+
migratedSkills,
|
|
679
|
+
dryRun: false,
|
|
680
|
+
});
|
|
681
|
+
}
|
|
682
|
+
catch (error) {
|
|
683
|
+
const err = error;
|
|
684
|
+
return formatter.fail({
|
|
685
|
+
code: err.code || 'CLEAN_FAILED',
|
|
686
|
+
message: err.message || 'Clean failed',
|
|
687
|
+
exitCode: err.exitCode ?? ExitCode.ERROR,
|
|
688
|
+
details: { platform, targetDir },
|
|
689
|
+
});
|
|
690
|
+
}
|
|
691
|
+
}
|
|
520
692
|
export { ExitCode } from '../utils/exit-codes.js';
|
|
521
693
|
export { OutputFormatter, createFormatter, parseOutputFormat } from '../utils/output.js';
|
|
522
694
|
export { computeChanges, isKitInstalled, loadManifest, updateKit } from './updater.js';
|
package/dist/lib/installer.js
CHANGED
|
@@ -12,10 +12,78 @@ export const PLATFORM_FOLDERS = {
|
|
|
12
12
|
agent: '.agent',
|
|
13
13
|
pi: '.pi/agent',
|
|
14
14
|
};
|
|
15
|
+
/**
|
|
16
|
+
* Copy universal skills from .agents/skills/ to the target directory.
|
|
17
|
+
* Uses the AgentSkills.io convention (.agents/skills/) which is discovered
|
|
18
|
+
* automatically by Pi, GitHub Copilot, and other agents.
|
|
19
|
+
*/
|
|
20
|
+
function copyUniversalSkills(targetDir) {
|
|
21
|
+
const sourceSkillsDir = path.join(PACKAGE_ROOT, '.agents', 'skills');
|
|
22
|
+
const targetSkillsDir = path.join(targetDir, '.agents', 'skills');
|
|
23
|
+
const copied = [];
|
|
24
|
+
const skipped = [];
|
|
25
|
+
if (!fs.existsSync(sourceSkillsDir)) {
|
|
26
|
+
return { copied, skipped };
|
|
27
|
+
}
|
|
28
|
+
if (!fs.existsSync(targetSkillsDir)) {
|
|
29
|
+
fs.mkdirSync(targetSkillsDir, { recursive: true });
|
|
30
|
+
}
|
|
31
|
+
for (const skillName of fs.readdirSync(sourceSkillsDir)) {
|
|
32
|
+
const src = path.join(sourceSkillsDir, skillName);
|
|
33
|
+
if (!fs.statSync(src).isDirectory())
|
|
34
|
+
continue;
|
|
35
|
+
const dest = path.join(targetSkillsDir, skillName);
|
|
36
|
+
if (fs.existsSync(dest)) {
|
|
37
|
+
skipped.push(skillName);
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
fs.cpSync(src, dest, { recursive: true });
|
|
41
|
+
copied.push(skillName);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return { copied, skipped };
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Merge custom skills from skills-custom/ into the target's universal skills directory.
|
|
48
|
+
* Only copies skills that don't already exist in the target (avoids overwriting
|
|
49
|
+
* upstream versions that may have been user-modified).
|
|
50
|
+
* Returns arrays of skill names that were merged or skipped.
|
|
51
|
+
*/
|
|
52
|
+
function mergeCustomSkills(targetDir) {
|
|
53
|
+
const customSkillsDir = path.join(PACKAGE_ROOT, 'skills-custom');
|
|
54
|
+
if (!fs.existsSync(customSkillsDir)) {
|
|
55
|
+
return { merged: [], skipped: [] };
|
|
56
|
+
}
|
|
57
|
+
const targetSkills = path.join(targetDir, '.agents', 'skills');
|
|
58
|
+
const merged = [];
|
|
59
|
+
const skipped = [];
|
|
60
|
+
for (const skillName of fs.readdirSync(customSkillsDir)) {
|
|
61
|
+
const src = path.join(customSkillsDir, skillName);
|
|
62
|
+
if (!fs.statSync(src).isDirectory())
|
|
63
|
+
continue;
|
|
64
|
+
const dest = path.join(targetSkills, skillName);
|
|
65
|
+
if (fs.existsSync(dest)) {
|
|
66
|
+
// Don't overwrite — upstream or user version takes priority
|
|
67
|
+
skipped.push(skillName);
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
fs.mkdirSync(path.dirname(dest), { recursive: true });
|
|
71
|
+
fs.cpSync(src, dest, { recursive: true });
|
|
72
|
+
merged.push(skillName);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return { merged, skipped };
|
|
76
|
+
}
|
|
15
77
|
/**
|
|
16
78
|
* Installs the WordPress Agent Kit into the specified directory for a given platform.
|
|
17
79
|
* If the kit is already installed, uses safe update logic to preserve user modifications.
|
|
18
80
|
*
|
|
81
|
+
* Installation layout:
|
|
82
|
+
* - .agents/skills/ — Universal skills (AgentSkills.io convention)
|
|
83
|
+
* - .github/ (or .pi/agent/, etc.) — Platform-specific agents, instructions, prompts
|
|
84
|
+
* - AGENTS.md — Project-level agent instructions
|
|
85
|
+
* - AGENTS.template.md — Template reference for future updates
|
|
86
|
+
*
|
|
19
87
|
* @param targetDir - The directory where the kit should be installed.
|
|
20
88
|
* @param platform - The target platform (github, cursor, claude, agent, pi)
|
|
21
89
|
* @returns InstallKitResult with details of what was created/skipped
|
|
@@ -31,6 +99,49 @@ export function installKit(targetDir, platform = 'github', options = {}) {
|
|
|
31
99
|
// Fresh install or fallback to full replacement
|
|
32
100
|
return fullInstall(targetDir, platform, force);
|
|
33
101
|
}
|
|
102
|
+
/**
|
|
103
|
+
* Migrate legacy skill directories to the universal .agents/skills/ convention.
|
|
104
|
+
* Detects skills in platform-specific directories (e.g., .github/skills/, .pi/agent/skills/)
|
|
105
|
+
* and moves them to .agents/skills/ if they don't already exist there.
|
|
106
|
+
* Returns lists of migrated and removed skill names.
|
|
107
|
+
*/
|
|
108
|
+
function migrateLegacySkills(targetDir, platform) {
|
|
109
|
+
const platformFolder = PLATFORM_FOLDERS[platform];
|
|
110
|
+
const legacySkillsDir = path.join(targetDir, platformFolder, 'skills');
|
|
111
|
+
const universalSkillsDir = path.join(targetDir, '.agents', 'skills');
|
|
112
|
+
const migrated = [];
|
|
113
|
+
const removed = [];
|
|
114
|
+
if (!fs.existsSync(legacySkillsDir)) {
|
|
115
|
+
return { migrated, removed };
|
|
116
|
+
}
|
|
117
|
+
// Ensure universal directory exists
|
|
118
|
+
if (!fs.existsSync(universalSkillsDir)) {
|
|
119
|
+
fs.mkdirSync(universalSkillsDir, { recursive: true });
|
|
120
|
+
}
|
|
121
|
+
for (const skillName of fs.readdirSync(legacySkillsDir)) {
|
|
122
|
+
const srcPath = path.join(legacySkillsDir, skillName);
|
|
123
|
+
const destPath = path.join(universalSkillsDir, skillName);
|
|
124
|
+
if (!fs.statSync(srcPath).isDirectory())
|
|
125
|
+
continue;
|
|
126
|
+
if (!fs.existsSync(destPath)) {
|
|
127
|
+
// Migrate: copy to universal location
|
|
128
|
+
fs.cpSync(srcPath, destPath, { recursive: true });
|
|
129
|
+
migrated.push(skillName);
|
|
130
|
+
}
|
|
131
|
+
else {
|
|
132
|
+
// Already exists in universal location — just remove from legacy
|
|
133
|
+
removed.push(skillName);
|
|
134
|
+
}
|
|
135
|
+
// Remove from legacy location
|
|
136
|
+
fs.rmSync(srcPath, { recursive: true, force: true });
|
|
137
|
+
}
|
|
138
|
+
// Remove the legacy skills directory if empty
|
|
139
|
+
const remaining = fs.readdirSync(legacySkillsDir);
|
|
140
|
+
if (remaining.length === 0) {
|
|
141
|
+
fs.rmSync(legacySkillsDir, { recursive: true, force: true });
|
|
142
|
+
}
|
|
143
|
+
return { migrated, removed };
|
|
144
|
+
}
|
|
34
145
|
/**
|
|
35
146
|
* Check if kit is already installed for a platform.
|
|
36
147
|
*/
|
|
@@ -53,18 +164,23 @@ function fullInstall(targetDir, platform, _force) {
|
|
|
53
164
|
const sourceGithub = path.join(PACKAGE_ROOT, '.github');
|
|
54
165
|
const filesCreated = [];
|
|
55
166
|
const filesSkipped = [];
|
|
56
|
-
// Copy platform-specific folder
|
|
167
|
+
// Copy platform-specific folder (agents, instructions — NOT skills)
|
|
57
168
|
const targetPlatform = path.join(targetDir, platformFolder);
|
|
58
169
|
if (fs.existsSync(targetPlatform)) {
|
|
59
170
|
fs.rmSync(targetPlatform, { recursive: true, force: true });
|
|
60
171
|
}
|
|
61
172
|
if (fs.existsSync(sourceGithub)) {
|
|
62
173
|
fs.cpSync(sourceGithub, targetPlatform, { recursive: true });
|
|
174
|
+
// Remove skills from platform dir — skills go to .agents/skills/ instead
|
|
175
|
+
const platformSkills = path.join(targetPlatform, 'skills');
|
|
176
|
+
if (fs.existsSync(platformSkills)) {
|
|
177
|
+
fs.rmSync(platformSkills, { recursive: true, force: true });
|
|
178
|
+
}
|
|
63
179
|
}
|
|
64
180
|
else {
|
|
65
181
|
throw new Error('Could not find source .github directory.');
|
|
66
182
|
}
|
|
67
|
-
// Collect created files
|
|
183
|
+
// Collect created files (excluding skills which are in .agents/)
|
|
68
184
|
const collectFiles = (dir, prefix) => {
|
|
69
185
|
if (!fs.existsSync(dir))
|
|
70
186
|
return;
|
|
@@ -81,6 +197,30 @@ function fullInstall(targetDir, platform, _force) {
|
|
|
81
197
|
}
|
|
82
198
|
};
|
|
83
199
|
collectFiles(targetPlatform, platformFolder);
|
|
200
|
+
// Migrate legacy skills from platform-specific dir to .agents/skills/
|
|
201
|
+
const migrationResult = migrateLegacySkills(targetDir, platform);
|
|
202
|
+
for (const skill of migrationResult.migrated) {
|
|
203
|
+
filesCreated.push(`.agents/skills/${skill} (migrated from ${platformFolder}/skills/)`);
|
|
204
|
+
}
|
|
205
|
+
for (const skill of migrationResult.removed) {
|
|
206
|
+
filesSkipped.push(`.agents/skills/${skill} (already existed, removed legacy copy)`);
|
|
207
|
+
}
|
|
208
|
+
// Copy universal skills to .agents/skills/ (AgentSkills.io convention)
|
|
209
|
+
const universalResult = copyUniversalSkills(targetDir);
|
|
210
|
+
for (const skill of universalResult.copied) {
|
|
211
|
+
filesCreated.push(`.agents/skills/${skill}`);
|
|
212
|
+
}
|
|
213
|
+
for (const skill of universalResult.skipped) {
|
|
214
|
+
filesSkipped.push(`.agents/skills/${skill} (already exists, preserved)`);
|
|
215
|
+
}
|
|
216
|
+
// Merge custom skills from skills-custom/ (e.g., wp-wpengine)
|
|
217
|
+
const customResult = mergeCustomSkills(targetDir);
|
|
218
|
+
for (const skill of customResult.merged) {
|
|
219
|
+
filesCreated.push(`.agents/skills/${skill}`);
|
|
220
|
+
}
|
|
221
|
+
for (const skill of customResult.skipped) {
|
|
222
|
+
filesSkipped.push(`.agents/skills/${skill} (already exists, preserved)`);
|
|
223
|
+
}
|
|
84
224
|
// Copy AGENTS.md template
|
|
85
225
|
const targetAgentsTemplate = path.join(targetDir, 'AGENTS.template.md');
|
|
86
226
|
if (fs.existsSync(templatePath)) {
|
|
@@ -140,6 +280,30 @@ function safeUpdateInstall(targetDir, platform, options) {
|
|
|
140
280
|
else {
|
|
141
281
|
filesSkipped.push('AGENTS.md (preserved)');
|
|
142
282
|
}
|
|
283
|
+
// Migrate legacy skills from platform-specific dir to .agents/skills/
|
|
284
|
+
const migrationResult = migrateLegacySkills(targetDir, platform);
|
|
285
|
+
for (const skill of migrationResult.migrated) {
|
|
286
|
+
filesCreated.push(`.agents/skills/${skill} (migrated from ${PLATFORM_FOLDERS[platform]}/skills/)`);
|
|
287
|
+
}
|
|
288
|
+
for (const skill of migrationResult.removed) {
|
|
289
|
+
filesSkipped.push(`.agents/skills/${skill} (already existed, removed legacy copy)`);
|
|
290
|
+
}
|
|
291
|
+
// Copy universal skills to .agents/skills/ (AgentSkills.io convention)
|
|
292
|
+
const universalResult = copyUniversalSkills(targetDir);
|
|
293
|
+
for (const skill of universalResult.copied) {
|
|
294
|
+
filesCreated.push(`.agents/skills/${skill}`);
|
|
295
|
+
}
|
|
296
|
+
for (const skill of universalResult.skipped) {
|
|
297
|
+
filesSkipped.push(`.agents/skills/${skill} (already exists, preserved)`);
|
|
298
|
+
}
|
|
299
|
+
// Merge custom skills from skills-custom/ (e.g., wp-wpengine)
|
|
300
|
+
const customResult = mergeCustomSkills(targetDir);
|
|
301
|
+
for (const skill of customResult.merged) {
|
|
302
|
+
filesCreated.push(`.agents/skills/${skill}`);
|
|
303
|
+
}
|
|
304
|
+
for (const skill of customResult.skipped) {
|
|
305
|
+
filesSkipped.push(`.agents/skills/${skill} (already exists, preserved)`);
|
|
306
|
+
}
|
|
143
307
|
return {
|
|
144
308
|
targetDir,
|
|
145
309
|
platform,
|