@skunkceo/cli 1.0.0 → 1.0.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/bin/setup.js ADDED
@@ -0,0 +1,272 @@
1
+ #!/usr/bin/env node
2
+
3
+ const https = require('https');
4
+ const fs = require('fs');
5
+ const path = require('path');
6
+ const { execSync } = require('child_process');
7
+ const readline = require('readline');
8
+
9
+ // ═══════════════════════════════════════════════════════════════════════════
10
+ // ASCII Art
11
+ // ═══════════════════════════════════════════════════════════════════════════
12
+
13
+ const SKUNK_LOGO = `
14
+ ███████╗██╗ ██╗██╗ ██╗███╗ ██╗██╗ ██╗
15
+ ██╔════╝██║ ██╔╝██║ ██║████╗ ██║██║ ██╔╝
16
+ ███████╗█████╔╝ ██║ ██║██╔██╗ ██║█████╔╝
17
+ ╚════██║██╔═██╗ ██║ ██║██║╚██╗██║██╔═██╗
18
+ ███████║██║ ██╗╚██████╔╝██║ ╚████║██║ ██╗
19
+ ╚══════╝╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═══╝╚═╝ ╚═╝
20
+ GLOBAL
21
+ `;
22
+
23
+ // ═══════════════════════════════════════════════════════════════════════════
24
+ // Utilities
25
+ // ═══════════════════════════════════════════════════════════════════════════
26
+
27
+ const colors = {
28
+ reset: '\x1b[0m',
29
+ bright: '\x1b[1m',
30
+ dim: '\x1b[2m',
31
+ green: '\x1b[32m',
32
+ yellow: '\x1b[33m',
33
+ red: '\x1b[31m',
34
+ cyan: '\x1b[36m',
35
+ magenta: '\x1b[35m',
36
+ white: '\x1b[37m',
37
+ };
38
+
39
+ function log(msg = '') {
40
+ console.log(msg);
41
+ }
42
+
43
+ function success(msg) {
44
+ console.log(`${colors.green}✓${colors.reset} ${msg}`);
45
+ }
46
+
47
+ function warn(msg) {
48
+ console.log(`${colors.yellow}!${colors.reset} ${msg}`);
49
+ }
50
+
51
+ function error(msg) {
52
+ console.log(`${colors.red}✗${colors.reset} ${msg}`);
53
+ }
54
+
55
+ function step(num, total, msg) {
56
+ console.log(`\n${colors.cyan}[${num}/${total}]${colors.reset} ${colors.bright}${msg}${colors.reset}`);
57
+ }
58
+
59
+ function commandExists(cmd) {
60
+ try {
61
+ execSync(`which ${cmd}`, { stdio: 'ignore' });
62
+ return true;
63
+ } catch {
64
+ return false;
65
+ }
66
+ }
67
+
68
+ function getVersion(cmd) {
69
+ try {
70
+ return execSync(`${cmd} --version`, { encoding: 'utf8' }).trim().split('\n')[0];
71
+ } catch {
72
+ return null;
73
+ }
74
+ }
75
+
76
+ // ═══════════════════════════════════════════════════════════════════════════
77
+ // Prompts
78
+ // ═══════════════════════════════════════════════════════════════════════════
79
+
80
+ const rl = readline.createInterface({
81
+ input: process.stdin,
82
+ output: process.stdout,
83
+ });
84
+
85
+ function ask(question) {
86
+ return new Promise((resolve) => {
87
+ rl.question(question, resolve);
88
+ });
89
+ }
90
+
91
+ async function confirm(question, defaultYes = true) {
92
+ const hint = defaultYes ? '(Y/n)' : '(y/N)';
93
+ const answer = await ask(`${question} ${hint} `);
94
+ if (!answer) return defaultYes;
95
+ return answer.toLowerCase().startsWith('y');
96
+ }
97
+
98
+ // ═══════════════════════════════════════════════════════════════════════════
99
+ // Skill Installation
100
+ // ═══════════════════════════════════════════════════════════════════════════
101
+
102
+ async function installSkill(skillName) {
103
+ const skillsDir = path.join(process.env.HOME, '.openclaw', 'skills');
104
+ const skillDir = path.join(skillsDir, skillName);
105
+
106
+ if (fs.existsSync(skillDir)) {
107
+ return { status: 'exists' };
108
+ }
109
+
110
+ // Fetch from GitHub
111
+ const files = ['SKILL.md', 'config.json'];
112
+ fs.mkdirSync(skillDir, { recursive: true });
113
+
114
+ for (const file of files) {
115
+ const url = `https://raw.githubusercontent.com/skunkceo/openclaw-skills/main/skills/${skillName}/${file}`;
116
+ try {
117
+ const content = await fetchFile(url);
118
+ if (content) {
119
+ fs.writeFileSync(path.join(skillDir, file), content);
120
+ }
121
+ } catch (e) {
122
+ // Optional files may not exist
123
+ }
124
+ }
125
+
126
+ if (fs.existsSync(path.join(skillDir, 'SKILL.md'))) {
127
+ return { status: 'installed' };
128
+ } else {
129
+ fs.rmSync(skillDir, { recursive: true, force: true });
130
+ return { status: 'failed' };
131
+ }
132
+ }
133
+
134
+ function fetchFile(url) {
135
+ return new Promise((resolve, reject) => {
136
+ https.get(url, { headers: { 'User-Agent': 'skunk-cli' } }, (res) => {
137
+ if (res.statusCode === 404) {
138
+ resolve(null);
139
+ return;
140
+ }
141
+ if (res.statusCode !== 200) {
142
+ reject(new Error(`HTTP ${res.statusCode}`));
143
+ return;
144
+ }
145
+ let data = '';
146
+ res.on('data', (chunk) => (data += chunk));
147
+ res.on('end', () => resolve(data));
148
+ }).on('error', reject);
149
+ });
150
+ }
151
+
152
+ // ═══════════════════════════════════════════════════════════════════════════
153
+ // Main Setup Flow
154
+ // ═══════════════════════════════════════════════════════════════════════════
155
+
156
+ async function main() {
157
+ console.clear();
158
+
159
+ // Show splash
160
+ log(colors.bright + SKUNK_LOGO + colors.reset);
161
+ log('');
162
+ log(`${colors.dim}Welcome! Let's get your AI-powered WordPress toolkit ready.${colors.reset}`);
163
+ log('');
164
+
165
+ const totalSteps = 3;
166
+
167
+ // ─────────────────────────────────────────────────────────────────────────
168
+ // Step 1: Environment checks
169
+ // ─────────────────────────────────────────────────────────────────────────
170
+ step(1, totalSteps, 'Checking environment...');
171
+
172
+ // Node.js
173
+ const nodeVersion = getVersion('node');
174
+ if (nodeVersion) {
175
+ success(`Node.js ${nodeVersion}`);
176
+ } else {
177
+ error('Node.js not found');
178
+ log('\n Install Node.js: https://nodejs.org/');
179
+ process.exit(1);
180
+ }
181
+
182
+ // WordPress Studio
183
+ let studioExists = commandExists('studio');
184
+
185
+ if (studioExists) {
186
+ const studioVersion = getVersion('studio');
187
+ success(`WordPress Studio installed ${studioVersion ? `(${studioVersion})` : ''}`);
188
+ } else {
189
+ warn('WordPress Studio not found');
190
+ log('');
191
+ log(' WordPress Studio is needed to create and manage WordPress sites.');
192
+ log('');
193
+ log(' Install it from: https://developer.wordpress.org/studio/');
194
+ log('');
195
+ log(' macOS: brew install --cask wordpress-studio');
196
+ log(' Other: Download from the website');
197
+ log('');
198
+
199
+ const proceed = await confirm('Continue setup anyway?', true);
200
+ if (!proceed) {
201
+ log('\n Run `skunk setup` again after installing WordPress Studio.');
202
+ rl.close();
203
+ process.exit(0);
204
+ }
205
+ }
206
+
207
+ // ─────────────────────────────────────────────────────────────────────────
208
+ // Step 2: Install AI Skills
209
+ // ─────────────────────────────────────────────────────────────────────────
210
+ step(2, totalSteps, 'Installing AI skills...');
211
+ log('');
212
+ log(` ${colors.dim}Skills teach your AI assistant how to work with WordPress${colors.reset}`);
213
+ log(` ${colors.dim}and Skunk products. Installing the essentials...${colors.reset}`);
214
+ log('');
215
+
216
+ // Core skills that enable WordPress + Skunk workflow
217
+ const coreSkills = [
218
+ { name: 'wordpress-studio', desc: 'WordPress site management' },
219
+ { name: 'woocommerce', desc: 'WooCommerce store operations' },
220
+ { name: 'skunkcrm', desc: 'SkunkCRM contact & pipeline management' },
221
+ { name: 'skunkforms', desc: 'SkunkForms form building' },
222
+ { name: 'skunkpages', desc: 'SkunkPages landing page optimization' },
223
+ ];
224
+
225
+ for (const skill of coreSkills) {
226
+ process.stdout.write(` ${skill.name} `);
227
+ const result = await installSkill(skill.name);
228
+ if (result.status === 'installed') {
229
+ log(`${colors.green}✓${colors.reset} ${colors.dim}${skill.desc}${colors.reset}`);
230
+ } else if (result.status === 'exists') {
231
+ log(`${colors.dim}✓ already installed${colors.reset}`);
232
+ } else {
233
+ log(`${colors.yellow}! not available yet${colors.reset}`);
234
+ }
235
+ }
236
+
237
+ // ─────────────────────────────────────────────────────────────────────────
238
+ // Step 3: Done!
239
+ // ─────────────────────────────────────────────────────────────────────────
240
+ step(3, totalSteps, 'Ready!');
241
+ log('');
242
+ log(` ${colors.green}Your AI assistant now knows WordPress and Skunk!${colors.reset}`);
243
+ log('');
244
+ log(' Next steps:');
245
+ log('');
246
+
247
+ if (studioExists) {
248
+ log(' 1. Create a WordPress site:');
249
+ log(` ${colors.cyan}studio create my-site${colors.reset}`);
250
+ log('');
251
+ log(' 2. Start chatting with your AI:');
252
+ log(` ${colors.cyan}"Install WooCommerce"${colors.reset}`);
253
+ log(` ${colors.cyan}"Install SkunkCRM"${colors.reset}`);
254
+ log(` ${colors.cyan}"Create a contact form"${colors.reset}`);
255
+ } else {
256
+ log(' 1. Install WordPress Studio');
257
+ log(' 2. Create a site: studio create my-site');
258
+ log(' 3. Chat with your AI to set up plugins');
259
+ }
260
+
261
+ log('');
262
+ log(` ${colors.dim}Guide: https://skunkglobal.com/guides/openclaw-wordpress${colors.reset}`);
263
+ log('');
264
+
265
+ rl.close();
266
+ }
267
+
268
+ // Run
269
+ main().catch((err) => {
270
+ console.error('Setup failed:', err.message);
271
+ process.exit(1);
272
+ });
package/bin/skunk.js CHANGED
@@ -14,6 +14,7 @@ const commands = {
14
14
  list: listSkills,
15
15
  available: listAvailable,
16
16
  remove: removeSkill,
17
+ setup: runSetup,
17
18
  help: showHelp,
18
19
  };
19
20
 
@@ -28,11 +29,17 @@ if (commands[command]) {
28
29
  showHelp();
29
30
  }
30
31
 
32
+ function runSetup() {
33
+ const setupPath = path.join(__dirname, 'setup.js');
34
+ require(setupPath);
35
+ }
36
+
31
37
  function showHelp() {
32
38
  console.log(`
33
- 🦨 Skunk CLI - Install skills for OpenClaw
39
+ 🦨 Skunk CLI - Skunk Global Suite for OpenClaw
34
40
 
35
41
  Usage:
42
+ skunk setup Interactive setup wizard (start here!)
36
43
  skunk install <skill> Install a skill
37
44
  skunk remove <skill> Remove an installed skill
38
45
  skunk list List installed skills
@@ -40,11 +47,11 @@ Usage:
40
47
  skunk help Show this help
41
48
 
42
49
  Examples:
43
- skunk install wordpress-studio
44
- skunk install seo-analyzer
45
- skunk list
50
+ skunk setup # Full suite setup wizard
51
+ skunk install wordpress-studio # Install individual skill
52
+ skunk list # See what's installed
46
53
 
47
- Skills: https://github.com/skunkceo/openclaw-skills
54
+ Docs: https://skunkglobal.com/guides/openclaw-wordpress
48
55
  `);
49
56
  }
50
57
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@skunkceo/cli",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "Install and manage Skunk Global skills for OpenClaw",
5
5
  "bin": {
6
6
  "skunk": "./bin/skunk.js"