wordpress-agent-kit 0.2.1 → 0.2.2
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/workflows/ci.yml +44 -0
- package/.husky/pre-commit +7 -0
- package/CLI_REVIEW.md +250 -0
- package/README.md +124 -51
- package/biome.json +39 -0
- package/dist/cli.js +75 -4
- package/dist/commands/install.js +43 -10
- package/dist/commands/run-playground.js +59 -14
- package/dist/commands/setup.js +222 -163
- package/dist/commands/sync-skills.js +33 -60
- package/dist/commands/upgrade.js +182 -0
- package/dist/lib/api.js +456 -0
- package/dist/lib/triage-mapper.js +18 -20
- package/dist/utils/exit-codes.js +60 -0
- package/dist/utils/output.js +96 -0
- package/dist/utils/paths.js +1 -1
- package/dist/utils/run.js +1 -1
- package/kit-learnings.md +192 -0
- package/package.json +7 -2
|
@@ -1,70 +1,43 @@
|
|
|
1
1
|
import { Command } from 'commander';
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
2
|
+
import { syncSkillsApi } from '../lib/api.js';
|
|
3
|
+
import { OutputFormatter } from '../utils/output.js';
|
|
4
|
+
function isDryRunResult(result) {
|
|
5
|
+
return result.success && 'wouldExecute' in (result.data || {});
|
|
6
|
+
}
|
|
7
|
+
function isRegularResult(result) {
|
|
8
|
+
return result.success && !('wouldExecute' in (result.data || {}));
|
|
9
|
+
}
|
|
7
10
|
/**
|
|
8
11
|
* Command to sync skills from the official WordPress agent-skills repository.
|
|
9
|
-
*
|
|
12
|
+
* Supports --json, --ndjson, --dry-run flags.
|
|
10
13
|
*/
|
|
11
14
|
export const syncSkillsCommand = new Command('sync-skills')
|
|
12
|
-
.description('Sync skills from the official WordPress
|
|
13
|
-
.argument('[ref]', 'Branch or tag to checkout',
|
|
14
|
-
.
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
15
|
+
.description('Sync skills from the official WordPress/agent-skills repository')
|
|
16
|
+
.argument('[ref]', 'Branch or tag to checkout', 'trunk')
|
|
17
|
+
.option('--ref <ref>', 'Branch or tag to checkout (alias for argument)')
|
|
18
|
+
.action(async (refArg, options, command) => {
|
|
19
|
+
const globalOpts = command.parent?.opts() || {};
|
|
20
|
+
const ref = options.ref || refArg;
|
|
21
|
+
const result = await syncSkillsApi({
|
|
22
|
+
targetDir: process.cwd(),
|
|
23
|
+
ref,
|
|
24
|
+
dryRun: globalOpts.dryRun,
|
|
25
|
+
});
|
|
26
|
+
if (globalOpts.json || globalOpts.ndjson || globalOpts.quiet) {
|
|
27
|
+
process.exit(OutputFormatter.getExitCode(result));
|
|
19
28
|
}
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
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);
|
|
29
|
+
if (isRegularResult(result)) {
|
|
30
|
+
const data = result.data;
|
|
31
|
+
console.log(`✓ Synced ${data.skillsSynced} skills from WordPress/agent-skills@${ref}`);
|
|
32
|
+
console.log(` Method: ${data.method}`);
|
|
33
|
+
console.log(` Duration: ${data.durationMs}ms`);
|
|
31
34
|
}
|
|
32
|
-
else {
|
|
33
|
-
|
|
34
|
-
|
|
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;
|
|
35
|
+
else if (isDryRunResult(result)) {
|
|
36
|
+
// Dry-run result
|
|
37
|
+
console.log(`✓ Dry-run: ${result.data.summary.skillsSynced} skills would be synced`);
|
|
56
38
|
}
|
|
57
|
-
|
|
58
|
-
|
|
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 });
|
|
39
|
+
else {
|
|
40
|
+
console.error(`✗ Sync failed: ${result.error?.message}`);
|
|
64
41
|
}
|
|
65
|
-
|
|
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');
|
|
42
|
+
process.exit(result.success ? 0 : 1);
|
|
70
43
|
});
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
import { Command } from 'commander';
|
|
5
|
+
import { installKitApi } from '../lib/api.js';
|
|
6
|
+
import { PLATFORM_FOLDERS } from '../lib/installer.js';
|
|
7
|
+
import { ExitCode } from '../utils/exit-codes.js';
|
|
8
|
+
import { OutputFormatter, createFormatter } from '../utils/output.js';
|
|
9
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
10
|
+
const __dirname = path.dirname(__filename);
|
|
11
|
+
const PACKAGE_ROOT = path.resolve(__dirname, '..', '..');
|
|
12
|
+
function isDryRunResult(result) {
|
|
13
|
+
return result.success && 'wouldExecute' in (result.data || {});
|
|
14
|
+
}
|
|
15
|
+
function isRegularResult(result) {
|
|
16
|
+
return result.success && !('wouldExecute' in (result.data || {}));
|
|
17
|
+
}
|
|
18
|
+
/** Current package version */
|
|
19
|
+
const CURRENT_VERSION = (() => {
|
|
20
|
+
try {
|
|
21
|
+
const pkg = JSON.parse(fs.readFileSync(path.join(PACKAGE_ROOT, 'package.json'), 'utf-8'));
|
|
22
|
+
return pkg.version;
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
return '0.0.0';
|
|
26
|
+
}
|
|
27
|
+
})();
|
|
28
|
+
/** Version detection from installed kit */
|
|
29
|
+
function detectInstalledVersion(targetDir) {
|
|
30
|
+
// Check AGENTS.md for version marker
|
|
31
|
+
const agentsPath = path.join(targetDir, 'AGENTS.md');
|
|
32
|
+
if (fs.existsSync(agentsPath)) {
|
|
33
|
+
const content = fs.readFileSync(agentsPath, 'utf-8');
|
|
34
|
+
const match = content.match(/wp-agent-kit[:\s]+v?(\d+\.\d+\.\d+)/i);
|
|
35
|
+
if (match)
|
|
36
|
+
return match[1];
|
|
37
|
+
}
|
|
38
|
+
// Check package.json if exists in target
|
|
39
|
+
const pkgPath = path.join(targetDir, 'package.json');
|
|
40
|
+
if (fs.existsSync(pkgPath)) {
|
|
41
|
+
try {
|
|
42
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
|
|
43
|
+
if (pkg.devDependencies?.['wordpress-agent-kit']) {
|
|
44
|
+
return pkg.devDependencies['wordpress-agent-kit'].replace(/^[\^~]/, '');
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
// ignore
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
/** Detect which platforms are installed */
|
|
54
|
+
function detectInstalledPlatforms(targetDir) {
|
|
55
|
+
const platforms = ['github', 'cursor', 'claude', 'agent', 'pi'];
|
|
56
|
+
return platforms.filter((p) => fs.existsSync(path.join(targetDir, PLATFORM_FOLDERS[p])));
|
|
57
|
+
}
|
|
58
|
+
/** Compare semantic versions */
|
|
59
|
+
function compareVersions(a, b) {
|
|
60
|
+
const pa = a.split('.').map(Number);
|
|
61
|
+
const pb = b.split('.').map(Number);
|
|
62
|
+
for (let i = 0; i < 3; i++) {
|
|
63
|
+
if (pa[i] !== pb[i])
|
|
64
|
+
return pa[i] - pb[i];
|
|
65
|
+
}
|
|
66
|
+
return 0;
|
|
67
|
+
}
|
|
68
|
+
/** Upgrade command */
|
|
69
|
+
export const upgradeCommand = new Command('upgrade')
|
|
70
|
+
.description('Upgrade existing WordPress Agent Kit installation to latest version')
|
|
71
|
+
.argument('[dir]', 'Target directory', process.cwd())
|
|
72
|
+
.option('--platform <platform>', 'Specific platform to upgrade (github, cursor, claude, agent, pi, all)', 'all')
|
|
73
|
+
.option('--force', 'Overwrite local modifications', false)
|
|
74
|
+
.option('--check-only', 'Only check for updates, do not apply', false)
|
|
75
|
+
.option('--from-version <version>', 'Override detected current version')
|
|
76
|
+
.action(async (dir, options, command) => {
|
|
77
|
+
const globalOpts = command.parent?.opts() || {};
|
|
78
|
+
const targetDir = path.resolve(dir);
|
|
79
|
+
const formatter = createFormatter(globalOpts, 'upgrade', CURRENT_VERSION);
|
|
80
|
+
if (!fs.existsSync(targetDir)) {
|
|
81
|
+
const result = formatter.fail({
|
|
82
|
+
code: 'NOT_FOUND',
|
|
83
|
+
message: `Target directory does not exist: ${targetDir}`,
|
|
84
|
+
exitCode: ExitCode.NOT_FOUND,
|
|
85
|
+
});
|
|
86
|
+
process.exit(OutputFormatter.getExitCode(result));
|
|
87
|
+
}
|
|
88
|
+
// Detect installed platforms
|
|
89
|
+
const platformsToCheck = options.platform === 'all'
|
|
90
|
+
? detectInstalledPlatforms(targetDir)
|
|
91
|
+
: [options.platform];
|
|
92
|
+
if (platformsToCheck.length === 0) {
|
|
93
|
+
const result = formatter.fail({
|
|
94
|
+
code: 'NOT_INSTALLED',
|
|
95
|
+
message: `No WordPress Agent Kit installation found in ${targetDir}`,
|
|
96
|
+
exitCode: ExitCode.NOT_FOUND,
|
|
97
|
+
});
|
|
98
|
+
process.exit(OutputFormatter.getExitCode(result));
|
|
99
|
+
}
|
|
100
|
+
// Detect or override version
|
|
101
|
+
let currentVersion = options.fromVersion;
|
|
102
|
+
if (!currentVersion) {
|
|
103
|
+
currentVersion = detectInstalledVersion(targetDir);
|
|
104
|
+
}
|
|
105
|
+
currentVersion = currentVersion || 'unknown';
|
|
106
|
+
const hasUpdate = currentVersion !== 'unknown' && compareVersions(CURRENT_VERSION, currentVersion) > 0;
|
|
107
|
+
const upgradeInfo = {
|
|
108
|
+
targetDir,
|
|
109
|
+
currentVersion,
|
|
110
|
+
latestVersion: CURRENT_VERSION,
|
|
111
|
+
hasUpdate,
|
|
112
|
+
platforms: platformsToCheck,
|
|
113
|
+
checkOnly: options.checkOnly,
|
|
114
|
+
};
|
|
115
|
+
if (globalOpts.json || globalOpts.quiet) {
|
|
116
|
+
const result = formatter.success(upgradeInfo);
|
|
117
|
+
process.exit(OutputFormatter.getExitCode(result));
|
|
118
|
+
}
|
|
119
|
+
// Human output
|
|
120
|
+
console.log('WordPress Agent Kit Upgrade Check');
|
|
121
|
+
console.log(` Target: ${targetDir}`);
|
|
122
|
+
console.log(` Current: ${currentVersion}`);
|
|
123
|
+
console.log(` Latest: ${CURRENT_VERSION}`);
|
|
124
|
+
console.log(` Platforms: ${platformsToCheck.join(', ')}`);
|
|
125
|
+
if (!hasUpdate && currentVersion !== 'unknown') {
|
|
126
|
+
console.log('\n✓ Already up to date');
|
|
127
|
+
process.exit(0);
|
|
128
|
+
}
|
|
129
|
+
if (currentVersion === 'unknown') {
|
|
130
|
+
console.log('\n⚠ Could not detect current version');
|
|
131
|
+
}
|
|
132
|
+
else {
|
|
133
|
+
console.log('\n✓ Update available');
|
|
134
|
+
}
|
|
135
|
+
if (options.checkOnly) {
|
|
136
|
+
console.log('\nDry run (--check-only): no changes made');
|
|
137
|
+
process.exit(0);
|
|
138
|
+
}
|
|
139
|
+
// Confirm upgrade in interactive mode
|
|
140
|
+
if (!globalOpts.json && !globalOpts.quiet) {
|
|
141
|
+
if (!options.force) {
|
|
142
|
+
console.log('\nUse --force to apply upgrade, or --check-only to preview');
|
|
143
|
+
process.exit(0);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
// Perform upgrade for each platform
|
|
147
|
+
const results = [];
|
|
148
|
+
for (const platform of platformsToCheck) {
|
|
149
|
+
const installResult = await installKitApi({
|
|
150
|
+
targetDir,
|
|
151
|
+
platform,
|
|
152
|
+
force: options.force,
|
|
153
|
+
dryRun: globalOpts.dryRun,
|
|
154
|
+
});
|
|
155
|
+
results.push({ platform, ...installResult });
|
|
156
|
+
}
|
|
157
|
+
const successCount = results.filter((r) => r.success).length;
|
|
158
|
+
const totalFiles = results.reduce((sum, r) => {
|
|
159
|
+
if (!r.success)
|
|
160
|
+
return sum;
|
|
161
|
+
if (isRegularResult(r)) {
|
|
162
|
+
return sum + (r.data.filesCreated.length || 0);
|
|
163
|
+
}
|
|
164
|
+
if (isDryRunResult(r)) {
|
|
165
|
+
// Dry-run - summary has filesCreated
|
|
166
|
+
return sum + (r.data.summary.filesCreated.length || 0);
|
|
167
|
+
}
|
|
168
|
+
return sum;
|
|
169
|
+
}, 0);
|
|
170
|
+
console.log(`\n✓ Upgraded ${successCount}/${results.length} platform(s)`);
|
|
171
|
+
console.log(` Files updated: ${totalFiles}`);
|
|
172
|
+
console.log(` Version: ${currentVersion} → ${CURRENT_VERSION}`);
|
|
173
|
+
const failed = results.filter((r) => !r.success);
|
|
174
|
+
if (failed.length > 0) {
|
|
175
|
+
console.error('\nFailures:');
|
|
176
|
+
for (const f of failed) {
|
|
177
|
+
console.error(` ${f.platform}: ${f.error?.message}`);
|
|
178
|
+
}
|
|
179
|
+
process.exit(1);
|
|
180
|
+
}
|
|
181
|
+
process.exit(0);
|
|
182
|
+
});
|