@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.
- package/bin/skunk.js +135 -24
- 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
|
|
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
|
-
|
|
16
|
-
|
|
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
|
-
|
|
23
|
-
|
|
21
|
+
slug: 'skunkforms',
|
|
22
|
+
proSlug: 'skunkforms-pro',
|
|
24
23
|
name: 'SkunkForms',
|
|
25
|
-
slug: 'skunk-forms',
|
|
26
|
-
requiresLicense: false,
|
|
27
24
|
},
|
|
28
25
|
'skunkpages': {
|
|
29
|
-
|
|
30
|
-
|
|
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
|
-
|
|
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
|
|