wordpress-agent-kit 0.2.1 → 0.3.0

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 (37) hide show
  1. package/.github/agents/wp-architect.agent.md +1 -0
  2. package/.github/skills/wordpress-router/SKILL.md +1 -0
  3. package/.github/skills/wp-abilities-api/SKILL.md +1 -0
  4. package/.github/skills/wp-block-development/SKILL.md +1 -0
  5. package/.github/skills/wp-block-themes/SKILL.md +1 -0
  6. package/.github/skills/wp-interactivity-api/SKILL.md +1 -0
  7. package/.github/skills/wp-performance/SKILL.md +1 -0
  8. package/.github/skills/wp-phpstan/SKILL.md +1 -0
  9. package/.github/skills/wp-playground/SKILL.md +1 -0
  10. package/.github/skills/wp-plugin-development/SKILL.md +1 -0
  11. package/.github/skills/wp-project-triage/SKILL.md +1 -0
  12. package/.github/skills/wp-rest-api/SKILL.md +1 -0
  13. package/.github/skills/wp-wpcli-and-ops/SKILL.md +1 -0
  14. package/.github/skills/wpds/SKILL.md +1 -0
  15. package/.github/workflows/ci.yml +44 -0
  16. package/.husky/pre-commit +7 -0
  17. package/AGENTS.md +33 -10
  18. package/AGENTS.template.md +63 -18
  19. package/CLI_REVIEW.md +250 -0
  20. package/README.md +240 -68
  21. package/biome.json +39 -0
  22. package/dist/cli.js +75 -4
  23. package/dist/commands/install.js +84 -10
  24. package/dist/commands/run-playground.js +59 -14
  25. package/dist/commands/setup.js +222 -163
  26. package/dist/commands/sync-skills.js +33 -60
  27. package/dist/commands/upgrade.js +211 -0
  28. package/dist/lib/api.js +511 -0
  29. package/dist/lib/installer.js +114 -6
  30. package/dist/lib/triage-mapper.js +18 -20
  31. package/dist/lib/updater.js +260 -0
  32. package/dist/utils/exit-codes.js +60 -0
  33. package/dist/utils/output.js +96 -0
  34. package/dist/utils/paths.js +1 -1
  35. package/dist/utils/run.js +1 -1
  36. package/extensions/wp-agent-kit/index.ts +630 -0
  37. package/package.json +27 -4
@@ -0,0 +1,630 @@
1
+ /**
2
+ * WordPress Agent Kit Pi Extension
3
+ *
4
+ * Provides Pi agents with WordPress development tools:
5
+ * - WordPress agent skills (13 skills covering plugin/theme/block dev, REST API, WP-CLI, etc.)
6
+ * - Project triage detection
7
+ * - Skill installation and syncing
8
+ * - Version upgrade management
9
+ *
10
+ * Compatible with Pi Coding Agent SDK (extensions.md spec).
11
+ */
12
+ import type { ExtensionAPI } from '@earendil-works/pi-coding-agent';
13
+ import { Type } from 'typebox';
14
+
15
+ // Import programmatic API for WordPress Agent Kit operations
16
+ import {
17
+ type InstallOptions,
18
+ type SyncOptions,
19
+ type TriageOptions,
20
+ computeChanges,
21
+ installKitApi,
22
+ isKitInstalled,
23
+ loadManifest,
24
+ runTriageApi,
25
+ syncSkillsApi,
26
+ } from '../../dist/lib/api.js';
27
+
28
+ export default function (pi: ExtensionAPI) {
29
+ // =========================================================================
30
+ // Skills Registration
31
+ // =========================================================================
32
+ // Register WordPress skills via resources_discover so Pi agents can use them.
33
+ // Skills are loaded from .github/skills/ (also declared in package.json pi.skills).
34
+ pi.on('resources_discover', async (_event, _ctx) => {
35
+ // Skills are auto-discovered from pi.skills in package.json.
36
+ // No additional configuration needed here — the manifest handles it.
37
+ return {};
38
+ });
39
+
40
+ // =========================================================================
41
+ // Session notifications
42
+ // =========================================================================
43
+ pi.on('session_start', async (_event, ctx) => {
44
+ const cwd = ctx.cwd;
45
+ if (isKitInstalled(cwd, 'github')) {
46
+ const manifest = loadManifest(cwd, 'github');
47
+ if (manifest) {
48
+ ctx.ui.setStatus('wp-agent-kit', `WP Agent Kit v${manifest.version}`);
49
+ }
50
+ }
51
+ });
52
+
53
+ // =========================================================================
54
+ // Custom Tools
55
+ // =========================================================================
56
+
57
+ // --- wp_triage ---
58
+ // Run WordPress project triage to detect project type, signals, and tooling.
59
+ pi.registerTool({
60
+ name: 'wp_triage',
61
+ label: 'WP Triage',
62
+ description:
63
+ 'Run WordPress project detection to classify the codebase (plugin, theme, block theme, WP core, Gutenberg). Returns project kind, signals (block.json, Interactivity API, WP-CLI, REST API), and tooling (PHP/Node). Use before making changes to a WordPress project.',
64
+ promptSnippet: 'Detect WordPress project type, signals, and tooling',
65
+ promptGuidelines: [
66
+ 'Use wp_triage before making changes to any WordPress project to understand the codebase structure.',
67
+ 'Use wp_triage output to route to the correct WordPress development skill.',
68
+ ],
69
+ parameters: Type.Object({
70
+ targetDir: Type.Optional(
71
+ Type.String({
72
+ description: 'Target directory to triage (defaults to current working directory)',
73
+ })
74
+ ),
75
+ platform: Type.Optional(
76
+ Type.String({
77
+ description:
78
+ 'Platform where skills are installed (github, cursor, claude, agent, pi). Default: github',
79
+ })
80
+ ),
81
+ }),
82
+ async execute(_toolCallId, params, _signal, _onUpdate, _ctx) {
83
+ const options: TriageOptions = {
84
+ targetDir: params.targetDir || process.cwd(),
85
+ platform: (params.platform as TriageOptions['platform']) || 'github',
86
+ };
87
+
88
+ const result = await runTriageApi(options);
89
+
90
+ if (!result.success) {
91
+ return {
92
+ content: [
93
+ {
94
+ type: 'text',
95
+ text: `Triage failed: ${result.error?.message || 'Unknown error'}`,
96
+ },
97
+ ],
98
+ details: { error: result.error },
99
+ isError: true,
100
+ };
101
+ }
102
+
103
+ const triage = result.data;
104
+ return {
105
+ content: [
106
+ {
107
+ type: 'text',
108
+ text: JSON.stringify(
109
+ {
110
+ project: triage.project,
111
+ signals: triage.signals,
112
+ tooling: triage.tooling,
113
+ recommendation: triage.project
114
+ ? `This appears to be a ${triage.project.primary} project (confidence: ${triage.project.confidence}). Use the appropriate wp-* skill for development.`
115
+ : 'Could not determine project type. Review signals manually.',
116
+ },
117
+ null,
118
+ 2
119
+ ),
120
+ },
121
+ ],
122
+ details: triage,
123
+ };
124
+ },
125
+ });
126
+
127
+ // --- wp_install_kit ---
128
+ // Install WordPress Agent Kit skills into a target directory.
129
+ pi.registerTool({
130
+ name: 'wp_install_kit',
131
+ label: 'WP Install Kit',
132
+ description:
133
+ 'Install the WordPress Agent Kit into a project directory. Copies .github/skills (13 WordPress development skills), agent definitions, instructions, and AGENTS.md template. Supports safe update mode that preserves user modifications. Use when setting up a new WordPress project or adding AI agent support.',
134
+ promptSnippet: 'Install WordPress AI agent skills and configuration into a project',
135
+ promptGuidelines: [
136
+ 'Use wp_install_kit when setting up a new WordPress project for AI agent development.',
137
+ 'Use wp_install_kit with dryRun:true to preview changes before applying.',
138
+ ],
139
+ parameters: Type.Object({
140
+ targetDir: Type.String({
141
+ description: 'Target directory to install into (the WordPress project root)',
142
+ }),
143
+ platform: Type.Optional(
144
+ Type.String({
145
+ description: 'Target platform: github, cursor, claude, agent, or pi. Default: github',
146
+ })
147
+ ),
148
+ dryRun: Type.Optional(
149
+ Type.Boolean({
150
+ description: 'If true, preview changes without making them. Default: false',
151
+ })
152
+ ),
153
+ force: Type.Optional(
154
+ Type.Boolean({
155
+ description: 'Overwrite user modifications on update. Default: false',
156
+ })
157
+ ),
158
+ }),
159
+ async execute(_toolCallId, params, _signal, onUpdate, _ctx) {
160
+ const options: InstallOptions = {
161
+ targetDir: params.targetDir,
162
+ platform: (params.platform as InstallOptions['platform']) || 'github',
163
+ dryRun: params.dryRun ?? false,
164
+ force: params.force ?? false,
165
+ safe: !params.force, // Default: safe unless forced
166
+ backup: true,
167
+ };
168
+
169
+ if (options.dryRun) {
170
+ onUpdate?.({
171
+ content: [
172
+ {
173
+ type: 'text',
174
+ text: 'Computing changes (dry-run)...',
175
+ },
176
+ ],
177
+ });
178
+ }
179
+
180
+ const result = await installKitApi(options);
181
+
182
+ if (!result.success) {
183
+ return {
184
+ content: [
185
+ {
186
+ type: 'text',
187
+ text: `Install failed: ${result.error?.message || 'Unknown error'}`,
188
+ },
189
+ ],
190
+ details: { error: result.error },
191
+ isError: true,
192
+ };
193
+ }
194
+
195
+ // Handle dry-run results
196
+ if (options.dryRun && 'wouldExecute' in (result.data || {})) {
197
+ const dryRun = result.data as {
198
+ wouldExecute: boolean;
199
+ actions: Array<{ type: string; description: string }>;
200
+ summary: Record<string, unknown>;
201
+ };
202
+ return {
203
+ content: [
204
+ {
205
+ type: 'text',
206
+ text: [
207
+ '# WordPress Agent Kit — Dry Run Preview',
208
+ '',
209
+ `Target: ${options.targetDir}`,
210
+ `Platform: ${options.platform}`,
211
+ '',
212
+ '## Changes',
213
+ ...dryRun.actions.map((a) => `- ${a.type}: ${a.description}`),
214
+ '',
215
+ 'Run without dryRun to apply these changes.',
216
+ ].join('\n'),
217
+ },
218
+ ],
219
+ details: dryRun,
220
+ };
221
+ }
222
+
223
+ // Handle real results
224
+ const data = result.data as {
225
+ filesCreated: string[];
226
+ filesSkipped: string[];
227
+ isUpdate: boolean;
228
+ backupDir: string | null;
229
+ conflicts?: string[];
230
+ };
231
+
232
+ const lines = [
233
+ data.isUpdate ? '# WordPress Agent Kit — Updated' : '# WordPress Agent Kit — Installed',
234
+ '',
235
+ `Target: ${options.targetDir}`,
236
+ `Platform: ${options.platform}`,
237
+ `Files created/updated: ${data.filesCreated.length}`,
238
+ ];
239
+
240
+ if (data.filesSkipped.length > 0) {
241
+ lines.push(`Files preserved: ${data.filesSkipped.length} (user-modified)`);
242
+ for (const skipped of data.filesSkipped.slice(0, 10)) {
243
+ lines.push(` - ${skipped}`);
244
+ }
245
+ }
246
+
247
+ if (data.conflicts && data.conflicts.length > 0) {
248
+ lines.push(
249
+ '',
250
+ `⚠ ${data.conflicts.length} conflict(s) — re-run with force:true to overwrite:`
251
+ );
252
+ for (const conflict of data.conflicts.slice(0, 5)) {
253
+ lines.push(` - ${conflict}`);
254
+ }
255
+ }
256
+
257
+ if (data.backupDir) {
258
+ lines.push('', `Backup created: ${data.backupDir}`);
259
+ }
260
+
261
+ lines.push(
262
+ '',
263
+ '## Next Steps',
264
+ '1. Run wp_triage to detect project type',
265
+ '2. Review AGENTS.md for project-specific guidance',
266
+ '3. Use `/skill:wp-project-triage` to begin development'
267
+ );
268
+
269
+ return {
270
+ content: [{ type: 'text', text: lines.join('\n') }],
271
+ details: data,
272
+ };
273
+ },
274
+ });
275
+
276
+ // --- wp_sync_skills ---
277
+ // Sync WordPress skills from upstream WordPress/agent-skills repo.
278
+ pi.registerTool({
279
+ name: 'wp_sync_skills',
280
+ label: 'WP Sync Skills',
281
+ description:
282
+ 'Sync WordPress agent skills from the upstream WordPress/agent-skills repository into the local project. Fetches the latest skill definitions and replaces the local .github/skills directory. Use when skills need updating from upstream.',
283
+ promptSnippet: 'Sync latest WordPress agent skills from upstream',
284
+ promptGuidelines: [
285
+ 'Use wp_sync_skills to pull the latest WordPress development skills from WordPress/agent-skills.',
286
+ 'Use wp_sync_skills with dryRun:true to preview before syncing.',
287
+ ],
288
+ parameters: Type.Object({
289
+ targetDir: Type.Optional(
290
+ Type.String({
291
+ description: 'Target directory (defaults to the project root running wp-agent-kit)',
292
+ })
293
+ ),
294
+ ref: Type.Optional(
295
+ Type.String({
296
+ description: 'Git ref to sync from (default: trunk)',
297
+ })
298
+ ),
299
+ dryRun: Type.Optional(
300
+ Type.Boolean({
301
+ description: 'If true, preview without applying. Default: false',
302
+ })
303
+ ),
304
+ }),
305
+ async execute(_toolCallId, params, _signal, onUpdate, _ctx) {
306
+ const options: SyncOptions = {
307
+ targetDir: params.targetDir || process.cwd(),
308
+ ref: params.ref || 'trunk',
309
+ dryRun: params.dryRun ?? false,
310
+ };
311
+
312
+ onUpdate?.({
313
+ content: [
314
+ {
315
+ type: 'text',
316
+ text: params.dryRun
317
+ ? 'Previewing skill sync (dry-run)...'
318
+ : `Syncing skills from WordPress/agent-skills@${options.ref}...`,
319
+ },
320
+ ],
321
+ });
322
+
323
+ const result = await syncSkillsApi(options);
324
+
325
+ if (!result.success) {
326
+ return {
327
+ content: [
328
+ {
329
+ type: 'text',
330
+ text: `Sync failed: ${result.error?.message || 'Unknown error'}`,
331
+ },
332
+ ],
333
+ details: { error: result.error },
334
+ isError: true,
335
+ };
336
+ }
337
+
338
+ if (options.dryRun && 'wouldExecute' in (result.data || {})) {
339
+ const dryRun = result.data as {
340
+ wouldExecute: boolean;
341
+ actions: Array<{ type: string; description: string }>;
342
+ };
343
+ return {
344
+ content: [
345
+ {
346
+ type: 'text',
347
+ text: [
348
+ '# Skill Sync — Dry Run',
349
+ '',
350
+ `Source: WordPress/agent-skills@${options.ref}`,
351
+ '',
352
+ '## Actions',
353
+ ...dryRun.actions.map((a) => `- ${a.type}: ${a.description}`),
354
+ '',
355
+ 'Run without dryRun to apply.',
356
+ ].join('\n'),
357
+ },
358
+ ],
359
+ details: dryRun,
360
+ };
361
+ }
362
+
363
+ const data = result.data as {
364
+ skillsSynced: number;
365
+ method: string;
366
+ sourceUrl: string;
367
+ };
368
+
369
+ return {
370
+ content: [
371
+ {
372
+ type: 'text',
373
+ text: [
374
+ '# Skills Synced',
375
+ '',
376
+ `Skills synced: ${data.skillsSynced}`,
377
+ `Method: ${data.method}`,
378
+ `Source: ${data.sourceUrl}`,
379
+ ].join('\n'),
380
+ },
381
+ ],
382
+ details: data,
383
+ };
384
+ },
385
+ });
386
+
387
+ // --- wp_upgrade ---
388
+ // Check and apply WordPress Agent Kit upgrades.
389
+ pi.registerTool({
390
+ name: 'wp_upgrade',
391
+ label: 'WP Upgrade',
392
+ description:
393
+ 'Check for WordPress Agent Kit updates and apply them. Shows current vs latest version, detects installed platforms, and can preview or apply the upgrade. Use to keep agent skills and configuration current.',
394
+ promptSnippet: 'Check and apply WordPress Agent Kit version upgrades',
395
+ promptGuidelines: [
396
+ 'Use wp_upgrade to check if the installed WordPress Agent Kit is up to date.',
397
+ 'Use wp_upgrade with checkOnly:true to preview without applying.',
398
+ ],
399
+ parameters: Type.Object({
400
+ targetDir: Type.Optional(
401
+ Type.String({
402
+ description: 'Target directory to check/upgrade (defaults to current working directory)',
403
+ })
404
+ ),
405
+ checkOnly: Type.Optional(
406
+ Type.Boolean({
407
+ description: 'Only check for updates, do not apply. Default: false',
408
+ })
409
+ ),
410
+ force: Type.Optional(
411
+ Type.Boolean({
412
+ description: 'Overwrite user modifications on upgrade. Default: false',
413
+ })
414
+ ),
415
+ }),
416
+ async execute(_toolCallId, params, _signal, _onUpdate, _ctx) {
417
+ const targetDir = params.targetDir || process.cwd();
418
+ const force = params.force ?? false;
419
+ const checkOnly = params.checkOnly ?? false;
420
+
421
+ // Detect installed platforms and current version
422
+ const fs = await import('node:fs');
423
+ const path = await import('node:path');
424
+ const pkgPath = path.join(
425
+ path.dirname(new URL(import.meta.url).pathname),
426
+ '..',
427
+ '..',
428
+ '..',
429
+ 'package.json'
430
+ );
431
+ let latestVersion = 'unknown';
432
+ try {
433
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
434
+ latestVersion = pkg.version;
435
+ } catch {
436
+ // fallback
437
+ }
438
+
439
+ const manifest = loadManifest(targetDir, 'github');
440
+ const currentVersion = manifest?.version || 'unknown';
441
+ const isInstalled = isKitInstalled(targetDir, 'github');
442
+
443
+ if (checkOnly) {
444
+ return {
445
+ content: [
446
+ {
447
+ type: 'text',
448
+ text: [
449
+ '# WordPress Agent Kit — Version Check',
450
+ '',
451
+ `Target: ${targetDir}`,
452
+ `Installed: ${isInstalled ? 'yes' : 'no'}`,
453
+ `Current version: ${currentVersion}`,
454
+ `Latest version: ${latestVersion}`,
455
+ '',
456
+ currentVersion !== latestVersion && isInstalled
457
+ ? '⚠ Update available. Run without checkOnly to apply.'
458
+ : isInstalled
459
+ ? '✓ Up to date.'
460
+ : 'Not installed. Use wp_install_kit to install.',
461
+ ].join('\n'),
462
+ },
463
+ ],
464
+ details: {
465
+ targetDir,
466
+ currentVersion,
467
+ latestVersion,
468
+ isInstalled,
469
+ },
470
+ };
471
+ }
472
+
473
+ // Apply upgrade
474
+ if (!isInstalled) {
475
+ return {
476
+ content: [
477
+ {
478
+ type: 'text',
479
+ text: 'Kit not installed. Use wp_install_kit to install first.',
480
+ },
481
+ ],
482
+ isError: true,
483
+ };
484
+ }
485
+
486
+ const result = await installKitApi({
487
+ targetDir,
488
+ platform: 'github',
489
+ force,
490
+ safe: !force,
491
+ backup: true,
492
+ });
493
+
494
+ if (!result.success) {
495
+ return {
496
+ content: [
497
+ {
498
+ type: 'text',
499
+ text: `Upgrade failed: ${result.error?.message || 'Unknown error'}`,
500
+ },
501
+ ],
502
+ isError: true,
503
+ };
504
+ }
505
+
506
+ const data = result.data as {
507
+ filesCreated: string[];
508
+ filesSkipped: string[];
509
+ conflicts?: string[];
510
+ backupDir: string | null;
511
+ };
512
+
513
+ const lines = [
514
+ '# WordPress Agent Kit — Upgraded',
515
+ '',
516
+ `Version: ${currentVersion} → ${latestVersion}`,
517
+ `Files updated: ${data.filesCreated.length}`,
518
+ ];
519
+
520
+ if (data.filesSkipped.length > 0) {
521
+ lines.push(`Files preserved: ${data.filesSkipped.length} (user-modified)`);
522
+ }
523
+ if (data.conflicts && data.conflicts.length > 0) {
524
+ lines.push(
525
+ '',
526
+ `⚠ ${data.conflicts.length} conflict(s) — re-run with force:true to overwrite.`
527
+ );
528
+ }
529
+ if (data.backupDir) {
530
+ lines.push(`Backup: ${data.backupDir}`);
531
+ }
532
+
533
+ return {
534
+ content: [{ type: 'text', text: lines.join('\n') }],
535
+ details: data,
536
+ };
537
+ },
538
+ });
539
+
540
+ // =========================================================================
541
+ // Commands
542
+ // =========================================================================
543
+
544
+ pi.registerCommand('wp-triage', {
545
+ description: 'Run WordPress project triage detection',
546
+ handler: async (args, ctx) => {
547
+ const targetDir = args?.trim() || ctx.cwd;
548
+ ctx.ui.setStatus('wp-triage', 'Running triage...');
549
+ const result = await runTriageApi({ targetDir });
550
+
551
+ if (!result.success) {
552
+ ctx.ui.notify(`Triage failed: ${result.error?.message}`, 'error');
553
+ return;
554
+ }
555
+
556
+ const triage = result.data;
557
+ const summary = triage.project
558
+ ? `${triage.project.primary} (confidence: ${triage.project.confidence})`
559
+ : 'unknown';
560
+ ctx.ui.notify(`Project: ${summary}`, 'info');
561
+ ctx.ui.setStatus('wp-triage', `Detected: ${summary}`);
562
+ },
563
+ });
564
+
565
+ pi.registerCommand('wp-install', {
566
+ description: 'Install WordPress Agent Kit into a project',
567
+ handler: async (args, ctx) => {
568
+ const targetDir = args?.trim() || ctx.cwd;
569
+ ctx.ui.setStatus('wp-install', 'Installing...');
570
+ const result = await installKitApi({
571
+ targetDir,
572
+ platform: 'github',
573
+ safe: true,
574
+ backup: true,
575
+ });
576
+
577
+ if (!result.success) {
578
+ ctx.ui.notify(`Install failed: ${result.error?.message}`, 'error');
579
+ return;
580
+ }
581
+
582
+ const data = result.data as { filesCreated: string[]; isUpdate: boolean };
583
+ const verb = data.isUpdate ? 'Updated' : 'Installed';
584
+ ctx.ui.notify(`${verb} (${data.filesCreated.length} files)`, 'info');
585
+ ctx.ui.setStatus('wp-install', `${verb} ${data.filesCreated.length} files`);
586
+ },
587
+ });
588
+
589
+ pi.registerCommand('wp-sync-skills', {
590
+ description: 'Sync WordPress skills from upstream',
591
+ handler: async (args, ctx) => {
592
+ ctx.ui.setStatus('wp-sync', 'Syncing skills...');
593
+ const result = await syncSkillsApi({
594
+ ref: args?.trim() || 'trunk',
595
+ });
596
+
597
+ if (!result.success) {
598
+ ctx.ui.notify(`Sync failed: ${result.error?.message}`, 'error');
599
+ return;
600
+ }
601
+
602
+ const data = result.data as { skillsSynced: number; method: string };
603
+ ctx.ui.notify(`Synced ${data.skillsSynced} skills (${data.method})`, 'info');
604
+ ctx.ui.setStatus('wp-sync', `${data.skillsSynced} skills`);
605
+ },
606
+ });
607
+
608
+ pi.registerCommand('wp-upgrade', {
609
+ description: 'Check or apply WordPress Agent Kit upgrades',
610
+ handler: async (_args, ctx) => {
611
+ const targetDir = ctx.cwd;
612
+ const manifest = loadManifest(targetDir, 'github');
613
+ const currentVersion = manifest?.version || 'not installed';
614
+
615
+ const pkgPath = `${ctx.cwd}/node_modules/wordpress-agent-kit/package.json`;
616
+ let latestVersion = 'unknown';
617
+ try {
618
+ const fs = await import('node:fs');
619
+ if (fs.existsSync(pkgPath)) {
620
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
621
+ latestVersion = pkg.version;
622
+ }
623
+ } catch {
624
+ // fallback
625
+ }
626
+
627
+ ctx.ui.notify(`WP Agent Kit: ${currentVersion} → ${latestVersion}`, 'info');
628
+ },
629
+ });
630
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wordpress-agent-kit",
3
- "version": "0.2.1",
3
+ "version": "0.3.0",
4
4
  "description": "WordPress-focused AGENTS.md + Agent Skills starter kit for AI coding agents.",
5
5
  "license": "GPL-2.0-or-later",
6
6
  "author": "Kyle Brodeur <kyle@brodeur.me> (https://brodeur.me)",
@@ -13,7 +13,8 @@
13
13
  "agents-md",
14
14
  "agent-skills",
15
15
  "ai-coding",
16
- "copilot"
16
+ "copilot",
17
+ "pi-package"
17
18
  ],
18
19
  "engines": {
19
20
  "node": ">=20.18"
@@ -21,28 +22,50 @@
21
22
  "bin": {
22
23
  "wp-agent-kit": "dist/cli.js"
23
24
  },
25
+ "exports": {
26
+ ".": "./dist/cli.js",
27
+ "./api": "./dist/lib/api.js"
28
+ },
29
+ "pi": {
30
+ "extensions": [
31
+ "./extensions/wp-agent-kit"
32
+ ],
33
+ "skills": [
34
+ "./.github/skills"
35
+ ]
36
+ },
24
37
  "dependencies": {
25
38
  "@clack/prompts": "^0.8.2",
26
39
  "commander": "^13.0.0"
27
40
  },
41
+ "peerDependencies": {
42
+ "@earendil-works/pi-coding-agent": "*",
43
+ "typebox": "*"
44
+ },
28
45
  "devDependencies": {
46
+ "@biomejs/biome": "1.9.4",
29
47
  "@eslint/js": "^9.17.0",
30
48
  "@types/node": "^22.10.1",
31
49
  "@vitest/coverage-v8": "^2.1.8",
32
50
  "eslint": "^9.16.0",
51
+ "husky": "^9.1.6",
33
52
  "prettier": "^3.4.1",
34
53
  "ts-node": "^10.9.2",
35
54
  "tsx": "^4.19.2",
36
55
  "typescript": "^5.7.2",
37
56
  "typescript-eslint": "^8.18.0",
38
57
  "vitest": "^2.1.8",
39
- "@earendil-works/pi-coding-agent": "^0.78.1"
58
+ "@earendil-works/pi-coding-agent": "^0.78.1",
59
+ "typebox": "*"
40
60
  },
41
61
  "scripts": {
42
62
  "dev": "tsx src/cli.ts",
43
63
  "build": "tsc",
44
64
  "check": "tsc --noEmit",
45
- "lint": "eslint src/ --fix",
65
+ "lint": "eslint src/ tests/ --fix && biome check --write .",
66
+ "lint:check": "eslint src/ tests/ && biome check .",
67
+ "format": "prettier --write . && biome format --write .",
68
+ "format:check": "prettier --check . && biome format --check .",
46
69
  "test": "vitest",
47
70
  "test:run": "vitest run",
48
71
  "test:coverage": "vitest run --coverage",