@skunkceo/cli 2.0.1 → 2.1.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 (2) hide show
  1. package/bin/skunk.js +135 -24
  2. package/package.json +1 -1
package/bin/skunk.js CHANGED
@@ -9,31 +9,28 @@ const SKILLS_REPO = 'skunkceo/openclaw-skills';
9
9
  const SKILLS_BRANCH = 'main';
10
10
  const OPENCLAW_DIR = path.join(process.env.HOME, '.openclaw', 'skills');
11
11
 
12
- // Plugin registry - maps plugin names to download URLs
12
+ // Plugin registry - maps plugin names to slugs
13
+ // All downloads go through skunkglobal.com/api/plugin-updates/download
13
14
  const PLUGIN_REGISTRY = {
14
15
  'skunkcrm': {
15
- free: 'https://skunkcrm.com/api/download/free',
16
- pro: 'https://skunkcrm.com/api/download/pro',
16
+ slug: 'skunkcrm',
17
+ proSlug: 'skunkcrm-pro',
17
18
  name: 'SkunkCRM',
18
- slug: 'skunk-crm',
19
- requiresLicense: false, // Pro requires license
20
19
  },
21
20
  'skunkforms': {
22
- free: 'https://skunkforms.com/api/download/free',
23
- pro: 'https://skunkforms.com/api/download/pro',
21
+ slug: 'skunkforms',
22
+ proSlug: 'skunkforms-pro',
24
23
  name: 'SkunkForms',
25
- slug: 'skunk-forms',
26
- requiresLicense: false,
27
24
  },
28
25
  'skunkpages': {
29
- free: 'https://skunkpages.com/api/download/free',
30
- pro: 'https://skunkpages.com/api/download/pro',
26
+ slug: 'skunkpages',
27
+ proSlug: 'skunkpages-pro',
31
28
  name: 'SkunkPages',
32
- slug: 'skunk-pages',
33
- requiresLicense: false,
34
29
  },
35
30
  };
36
31
 
32
+ const DOWNLOAD_BASE = 'https://skunkglobal.com/api/plugin-updates/download';
33
+
37
34
  const colors = {
38
35
  reset: '\x1b[0m',
39
36
  bright: '\x1b[1m',
@@ -69,6 +66,9 @@ switch (command) {
69
66
  case 'plugins':
70
67
  listPlugins();
71
68
  break;
69
+ case 'status':
70
+ checkStatus();
71
+ break;
72
72
  case 'update':
73
73
  handleUpdate();
74
74
  break;
@@ -303,11 +303,27 @@ To install WordPress plugins, you need either:
303
303
  return;
304
304
  }
305
305
 
306
- const downloadUrl = isPro ? plugin.pro : plugin.free;
306
+ // Build download URL
307
+ const slug = isPro ? plugin.proSlug : plugin.slug;
308
+ let downloadUrl = `${DOWNLOAD_BASE}?slug=${slug}`;
309
+
310
+ // Add license key for Pro versions
311
+ if (isPro && license) {
312
+ downloadUrl += `&license_key=${license}`;
313
+ }
314
+
307
315
  const displayName = isPro ? `${plugin.name} Pro` : plugin.name;
308
316
 
309
317
  console.log(`Installing ${displayName}...`);
310
318
 
319
+ // Pro requires license
320
+ if (isPro && !license) {
321
+ warn('Pro version requires a license key.');
322
+ console.log(` skunk install plugin ${name} --license=YOUR_LICENSE_KEY\n`);
323
+ console.log(`${colors.dim}Get a license at: https://skunkglobal.com/pricing${colors.reset}`);
324
+ return;
325
+ }
326
+
311
327
  // Build the command
312
328
  let cmd;
313
329
  if (hasStudio) {
@@ -316,22 +332,12 @@ To install WordPress plugins, you need either:
316
332
  cmd = `wp plugin install "${downloadUrl}" --activate`;
317
333
  }
318
334
 
319
- // Add license if Pro and license provided
320
- if (isPro && license) {
321
- console.log(`${colors.dim}License key provided${colors.reset}`);
322
- }
323
-
324
335
  console.log(`${colors.dim}Running: ${cmd}${colors.reset}\n`);
325
336
 
326
337
  try {
327
338
  execSync(cmd, { stdio: 'inherit' });
328
339
  success(`Installed ${displayName}`);
329
340
 
330
- // If Pro and license provided, try to activate
331
- if (isPro && license) {
332
- console.log(`\n${colors.yellow}!${colors.reset} License activation may require manual setup in WordPress admin.`);
333
- }
334
-
335
341
  // Suggest installing the skill too
336
342
  console.log(`\n${colors.dim}Tip: Install the AI skill to let your assistant manage ${plugin.name}:${colors.reset}`);
337
343
  console.log(` skunk install skill ${pluginKey}\n`);
@@ -356,6 +362,110 @@ Pro versions: skunk install plugin <name>-pro --license=XXXX${colors.reset}
356
362
  `);
357
363
  }
358
364
 
365
+ // ═══════════════════════════════════════════════════════════════════════════
366
+ // Status - Check plugin versions
367
+ // ═══════════════════════════════════════════════════════════════════════════
368
+
369
+ async function checkStatus() {
370
+ console.log('Checking plugin versions...\n');
371
+
372
+ // Fetch latest versions from API
373
+ const versionsUrl = 'https://skunkglobal.com/api/plugins/versions';
374
+
375
+ try {
376
+ const latestVersions = await new Promise((resolve, reject) => {
377
+ https.get(versionsUrl, { headers: { 'User-Agent': 'skunk-cli' } }, (res) => {
378
+ let data = '';
379
+ res.on('data', chunk => data += chunk);
380
+ res.on('end', () => {
381
+ try {
382
+ resolve(JSON.parse(data));
383
+ } catch (e) {
384
+ reject(new Error('Invalid response'));
385
+ }
386
+ });
387
+ }).on('error', reject);
388
+ });
389
+
390
+ if (!latestVersions.plugins) {
391
+ error('Failed to fetch version info');
392
+ return;
393
+ }
394
+
395
+ // Check if we're in a WordPress context (wp or studio available)
396
+ const hasWpCli = commandExists('wp');
397
+ const hasStudio = commandExists('studio');
398
+ const inWordPress = hasWpCli || hasStudio;
399
+
400
+ // Get installed versions if in WordPress context
401
+ let installedVersions = {};
402
+ if (inWordPress) {
403
+ try {
404
+ const cmd = hasStudio ? 'studio wp plugin list --format=json' : 'wp plugin list --format=json';
405
+ const output = execSync(cmd, { encoding: 'utf8', stdio: ['pipe', 'pipe', 'ignore'] });
406
+ const plugins = JSON.parse(output);
407
+
408
+ for (const p of plugins) {
409
+ // Map WP plugin slugs to our slugs
410
+ if (p.name === 'skunk-crm' || p.name === 'skunkcrm') {
411
+ installedVersions['skunkcrm'] = p.version;
412
+ } else if (p.name === 'skunk-forms' || p.name === 'skunkforms') {
413
+ installedVersions['skunkforms'] = p.version;
414
+ } else if (p.name === 'skunk-pages' || p.name === 'skunkpages') {
415
+ installedVersions['skunkpages'] = p.version;
416
+ }
417
+ }
418
+ } catch (e) {
419
+ // Couldn't get installed versions, that's ok
420
+ }
421
+ }
422
+
423
+ console.log(`${colors.bright}Plugin${colors.reset} ${colors.bright}Latest${colors.reset} ${inWordPress ? `${colors.bright}Installed${colors.reset}` : ''}`);
424
+ console.log('─'.repeat(inWordPress ? 50 : 30));
425
+
426
+ // Show free plugins
427
+ for (const [slug, info] of Object.entries(latestVersions.plugins)) {
428
+ if (info.type === 'free') {
429
+ const installed = installedVersions[slug];
430
+ const latestV = info.version;
431
+
432
+ let status = '';
433
+ if (installed) {
434
+ if (installed === latestV) {
435
+ status = `${colors.green}${installed}${colors.reset} ✓`;
436
+ } else {
437
+ status = `${colors.yellow}${installed}${colors.reset} → ${latestV}`;
438
+ }
439
+ } else if (inWordPress) {
440
+ status = `${colors.dim}not installed${colors.reset}`;
441
+ }
442
+
443
+ const padding = ' '.repeat(Math.max(0, 16 - slug.length));
444
+ const vPadding = ' '.repeat(Math.max(0, 10 - latestV.length));
445
+ console.log(`${slug}${padding}${latestV}${vPadding}${status}`);
446
+ }
447
+ }
448
+
449
+ console.log('');
450
+
451
+ // Show if updates available
452
+ const hasUpdates = Object.entries(installedVersions).some(([slug, v]) => {
453
+ const latest = latestVersions.plugins[slug];
454
+ return latest && latest.version !== v;
455
+ });
456
+
457
+ if (hasUpdates) {
458
+ console.log(`${colors.yellow}Updates available!${colors.reset} Run:`);
459
+ console.log(` skunk install plugin <name>\n`);
460
+ } else if (Object.keys(installedVersions).length > 0) {
461
+ console.log(`${colors.green}All plugins up to date!${colors.reset}\n`);
462
+ }
463
+
464
+ } catch (e) {
465
+ error('Failed to check versions: ' + e.message);
466
+ }
467
+ }
468
+
359
469
  // ═══════════════════════════════════════════════════════════════════════════
360
470
  // Update
361
471
  // ═══════════════════════════════════════════════════════════════════════════
@@ -417,6 +527,7 @@ ${colors.bright}Usage:${colors.reset}
417
527
  skunk list List installed skills
418
528
  skunk available List available skills
419
529
  skunk plugins List available plugins
530
+ skunk status Check plugin versions (+ compare if in WP site)
420
531
  skunk update Update CLI and refresh skills
421
532
  skunk help Show this help
422
533
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@skunkceo/cli",
3
- "version": "2.0.1",
3
+ "version": "2.1.0",
4
4
  "description": "Install and manage Skunk Global skills and WordPress plugins",
5
5
  "bin": {
6
6
  "skunk": "./bin/skunk.js"