@skunkceo/cli 1.0.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 (3) hide show
  1. package/README.md +43 -0
  2. package/bin/skunk.js +178 -0
  3. package/package.json +16 -0
package/README.md ADDED
@@ -0,0 +1,43 @@
1
+ # Skunk CLI
2
+
3
+ Install and manage [Skunk Global](https://skunkglobal.com) skills for OpenClaw.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install -g @skunkglobal/cli
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ```bash
14
+ # Install a skill
15
+ skunk install wordpress-studio
16
+
17
+ # List installed skills
18
+ skunk list
19
+
20
+ # See available skills
21
+ skunk available
22
+
23
+ # Remove a skill
24
+ skunk remove wordpress-studio
25
+ ```
26
+
27
+ ## Available Skills
28
+
29
+ Browse all skills at: https://github.com/skunkceo/openclaw-skills
30
+
31
+ ## What are Skills?
32
+
33
+ Skills teach OpenClaw how to use specific tools and services. Each skill contains instructions that help your AI assistant understand:
34
+
35
+ - What commands to run
36
+ - How to interpret results
37
+ - Best practices for the tool
38
+
39
+ ## Links
40
+
41
+ - [Skunk Global](https://skunkglobal.com)
42
+ - [Skills Repository](https://github.com/skunkceo/openclaw-skills)
43
+ - [OpenClaw](https://openclaw.ai)
package/bin/skunk.js ADDED
@@ -0,0 +1,178 @@
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
+
8
+ const SKILLS_REPO = 'skunkceo/openclaw-skills';
9
+ const SKILLS_BRANCH = 'main';
10
+ const OPENCLAW_DIR = path.join(process.env.HOME, '.openclaw', 'skills');
11
+
12
+ const commands = {
13
+ install: installSkill,
14
+ list: listSkills,
15
+ available: listAvailable,
16
+ remove: removeSkill,
17
+ help: showHelp,
18
+ };
19
+
20
+ const args = process.argv.slice(2);
21
+ const command = args[0] || 'help';
22
+ const skillName = args[1];
23
+
24
+ if (commands[command]) {
25
+ commands[command](skillName);
26
+ } else {
27
+ console.log(`Unknown command: ${command}`);
28
+ showHelp();
29
+ }
30
+
31
+ function showHelp() {
32
+ console.log(`
33
+ 🦨 Skunk CLI - Install skills for OpenClaw
34
+
35
+ Usage:
36
+ skunk install <skill> Install a skill
37
+ skunk remove <skill> Remove an installed skill
38
+ skunk list List installed skills
39
+ skunk available List available skills
40
+ skunk help Show this help
41
+
42
+ Examples:
43
+ skunk install wordpress-studio
44
+ skunk install seo-analyzer
45
+ skunk list
46
+
47
+ Skills: https://github.com/skunkceo/openclaw-skills
48
+ `);
49
+ }
50
+
51
+ function listSkills() {
52
+ if (!fs.existsSync(OPENCLAW_DIR)) {
53
+ console.log('No skills installed yet.');
54
+ return;
55
+ }
56
+
57
+ const skills = fs.readdirSync(OPENCLAW_DIR).filter(f => {
58
+ const skillPath = path.join(OPENCLAW_DIR, f);
59
+ return fs.statSync(skillPath).isDirectory() &&
60
+ fs.existsSync(path.join(skillPath, 'SKILL.md'));
61
+ });
62
+
63
+ if (skills.length === 0) {
64
+ console.log('No skills installed yet.');
65
+ } else {
66
+ console.log('Installed skills:');
67
+ skills.forEach(s => console.log(` - ${s}`));
68
+ }
69
+ }
70
+
71
+ async function listAvailable() {
72
+ console.log('Fetching available skills...\n');
73
+
74
+ const url = `https://api.github.com/repos/${SKILLS_REPO}/contents/skills?ref=${SKILLS_BRANCH}`;
75
+
76
+ https.get(url, { headers: { 'User-Agent': 'skunk-cli' } }, (res) => {
77
+ let data = '';
78
+ res.on('data', chunk => data += chunk);
79
+ res.on('end', () => {
80
+ try {
81
+ const skills = JSON.parse(data);
82
+ console.log('Available skills:');
83
+ skills.filter(s => s.type === 'dir').forEach(s => {
84
+ console.log(` - ${s.name}`);
85
+ });
86
+ console.log('\nInstall with: skunk install <skill-name>');
87
+ } catch (e) {
88
+ console.error('Failed to fetch skills list');
89
+ }
90
+ });
91
+ }).on('error', (e) => {
92
+ console.error('Failed to fetch skills:', e.message);
93
+ });
94
+ }
95
+
96
+ async function installSkill(name) {
97
+ if (!name) {
98
+ console.log('Usage: skunk install <skill-name>');
99
+ console.log('Run "skunk available" to see available skills');
100
+ return;
101
+ }
102
+
103
+ console.log(`Installing ${name}...`);
104
+
105
+ // Create skills directory if it doesn't exist
106
+ if (!fs.existsSync(OPENCLAW_DIR)) {
107
+ fs.mkdirSync(OPENCLAW_DIR, { recursive: true });
108
+ }
109
+
110
+ const skillDir = path.join(OPENCLAW_DIR, name);
111
+
112
+ if (fs.existsSync(skillDir)) {
113
+ console.log(`Skill ${name} is already installed. Remove it first with: skunk remove ${name}`);
114
+ return;
115
+ }
116
+
117
+ // Fetch skill files from GitHub
118
+ const files = ['SKILL.md', 'config.json', 'README.md'];
119
+ fs.mkdirSync(skillDir, { recursive: true });
120
+
121
+ let success = false;
122
+
123
+ for (const file of files) {
124
+ const url = `https://raw.githubusercontent.com/${SKILLS_REPO}/${SKILLS_BRANCH}/skills/${name}/${file}`;
125
+
126
+ try {
127
+ const content = await fetchFile(url);
128
+ if (content) {
129
+ fs.writeFileSync(path.join(skillDir, file), content);
130
+ if (file === 'SKILL.md') success = true;
131
+ }
132
+ } catch (e) {
133
+ // README might not exist, that's ok
134
+ }
135
+ }
136
+
137
+ if (success) {
138
+ console.log(`✓ Installed ${name} to ${skillDir}`);
139
+ } else {
140
+ fs.rmSync(skillDir, { recursive: true, force: true });
141
+ console.log(`✗ Skill "${name}" not found. Run "skunk available" to see available skills.`);
142
+ }
143
+ }
144
+
145
+ function removeSkill(name) {
146
+ if (!name) {
147
+ console.log('Usage: skunk remove <skill-name>');
148
+ return;
149
+ }
150
+
151
+ const skillDir = path.join(OPENCLAW_DIR, name);
152
+
153
+ if (!fs.existsSync(skillDir)) {
154
+ console.log(`Skill ${name} is not installed.`);
155
+ return;
156
+ }
157
+
158
+ fs.rmSync(skillDir, { recursive: true, force: true });
159
+ console.log(`✓ Removed ${name}`);
160
+ }
161
+
162
+ function fetchFile(url) {
163
+ return new Promise((resolve, reject) => {
164
+ https.get(url, { headers: { 'User-Agent': 'skunk-cli' } }, (res) => {
165
+ if (res.statusCode === 404) {
166
+ resolve(null);
167
+ return;
168
+ }
169
+ if (res.statusCode !== 200) {
170
+ reject(new Error(`HTTP ${res.statusCode}`));
171
+ return;
172
+ }
173
+ let data = '';
174
+ res.on('data', chunk => data += chunk);
175
+ res.on('end', () => resolve(data));
176
+ }).on('error', reject);
177
+ });
178
+ }
package/package.json ADDED
@@ -0,0 +1,16 @@
1
+ {
2
+ "name": "@skunkceo/cli",
3
+ "version": "1.0.0",
4
+ "description": "Install and manage Skunk Global skills for OpenClaw",
5
+ "bin": {
6
+ "skunk": "./bin/skunk.js"
7
+ },
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "https://github.com/skunkceo/skunk-cli"
11
+ },
12
+ "keywords": ["openclaw", "skills", "wordpress", "ai", "skunk"],
13
+ "author": "Skunk Global",
14
+ "license": "MIT",
15
+ "homepage": "https://skunkglobal.com/skills"
16
+ }