crabhub 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.
- package/bin/crabhub.js +148 -0
- package/package.json +15 -0
package/bin/crabhub.js
ADDED
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
'use strict';
|
|
4
|
+
|
|
5
|
+
const { spawn } = require('node:child_process');
|
|
6
|
+
|
|
7
|
+
// ===== 配置 =====
|
|
8
|
+
// 占位符在 build.sh 打包时会被替换为实际环境的 URL
|
|
9
|
+
const BASE_URL = 'https://callcrab.com';
|
|
10
|
+
|
|
11
|
+
// ===== 颜色 =====
|
|
12
|
+
const c = {
|
|
13
|
+
reset: '\x1b[0m',
|
|
14
|
+
bold: '\x1b[1m',
|
|
15
|
+
dim: '\x1b[2m',
|
|
16
|
+
green: '\x1b[32m',
|
|
17
|
+
yellow: '\x1b[33m',
|
|
18
|
+
blue: '\x1b[34m',
|
|
19
|
+
cyan: '\x1b[36m',
|
|
20
|
+
red: '\x1b[31m',
|
|
21
|
+
bgGreen: '\x1b[42m',
|
|
22
|
+
black: '\x1b[30m',
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
// ===== Banner =====
|
|
26
|
+
function printBanner() {
|
|
27
|
+
console.log(`
|
|
28
|
+
${c.cyan}${c.bold} ██████ ██████ █████ ██████ ██ ██ ██ ██ ██████ ${c.reset}
|
|
29
|
+
${c.cyan} ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██${c.reset}
|
|
30
|
+
${c.cyan} ██ ██████ ███████ ██████ ███████ ██ ██ ██████ ${c.reset}
|
|
31
|
+
${c.cyan} ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██${c.reset}
|
|
32
|
+
${c.cyan}${c.bold} ██████ ██ ██ ██ ██ ██████ ██ ██ ██████ ██████ ${c.reset}
|
|
33
|
+
`);
|
|
34
|
+
console.log(` ${c.bgGreen}${c.black} crabhub ${c.reset}\n`);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const HELP_TEXT = `
|
|
38
|
+
${c.dim}The skill platform CLI (powered by skills)${c.reset}
|
|
39
|
+
|
|
40
|
+
${c.bold}Usage:${c.reset} npx crabhub <command> <skill_slug>
|
|
41
|
+
|
|
42
|
+
${c.bold}Commands:${c.reset}
|
|
43
|
+
${c.green}install${c.reset} <skill_slug> Install a skill (delegates to skills package)
|
|
44
|
+
${c.green}add${c.reset} <skill_slug> Alias for install
|
|
45
|
+
|
|
46
|
+
${c.bold}Options:${c.reset}
|
|
47
|
+
--help, -h Show this help message
|
|
48
|
+
--version, -v Show version
|
|
49
|
+
|
|
50
|
+
${c.bold}Examples:${c.reset}
|
|
51
|
+
${c.dim}$${c.reset} npx crabhub install web_tools_guide
|
|
52
|
+
${c.dim}$${c.reset} npx crabhub add Ugj59d3SFo2T7Yq2mHEAgH
|
|
53
|
+
|
|
54
|
+
${c.dim}This CLI internally runs: npx -y skills add <url>${c.reset}
|
|
55
|
+
${c.dim}The skills package handles Agent selection, path mapping, and installation.${c.reset}
|
|
56
|
+
`;
|
|
57
|
+
|
|
58
|
+
function main() {
|
|
59
|
+
const args = process.argv.slice(2);
|
|
60
|
+
|
|
61
|
+
if (args.length === 0 || args.includes('--help') || args.includes('-h')) {
|
|
62
|
+
printBanner();
|
|
63
|
+
console.log(HELP_TEXT.trimEnd());
|
|
64
|
+
process.exit(0);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (args.includes('--version') || args.includes('-v')) {
|
|
68
|
+
const pkg = require('../package.json');
|
|
69
|
+
console.log(pkg.version);
|
|
70
|
+
process.exit(0);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const command = args[0];
|
|
74
|
+
|
|
75
|
+
if (command !== 'install' && command !== 'add') {
|
|
76
|
+
printBanner();
|
|
77
|
+
console.error(`${c.red}ERROR${c.reset} Unknown command: ${command}\n`);
|
|
78
|
+
console.log(`${c.bold}Available commands:${c.reset} install, add`);
|
|
79
|
+
console.log(`\nRun ${c.dim}npx crabhub --help${c.reset} for usage.`);
|
|
80
|
+
process.exit(1);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (args.length < 2) {
|
|
84
|
+
printBanner();
|
|
85
|
+
console.error(`${c.red}ERROR${c.reset} Missing required argument: ${c.yellow}skill_slug${c.reset}\n`);
|
|
86
|
+
console.log(`${c.bold}Usage:${c.reset}`);
|
|
87
|
+
console.log(` ${c.dim}$${c.reset} npx crabhub install skill_slug`);
|
|
88
|
+
console.log(`\n${c.bold}Example:${c.reset}`);
|
|
89
|
+
console.log(` ${c.dim}$${c.reset} npx crabhub install web_tools_guide`);
|
|
90
|
+
process.exit(1);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const identifier = args[1].trim();
|
|
94
|
+
if (!identifier) {
|
|
95
|
+
console.error(`${c.red}ERROR${c.reset} Empty skill identifier`);
|
|
96
|
+
process.exit(1);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const wellKnownUrl = buildWellKnownUrl(identifier);
|
|
100
|
+
|
|
101
|
+
// 透传剩余参数给 skills 包
|
|
102
|
+
const extraArgs = args.slice(2);
|
|
103
|
+
const skillsArgs = ['-y', 'skills', 'add', wellKnownUrl, ...extraArgs];
|
|
104
|
+
|
|
105
|
+
console.log(`${c.dim}Running: npx ${skillsArgs.join(' ')}${c.reset}\n`);
|
|
106
|
+
|
|
107
|
+
// spawn npx -y skills add <url>,stdio 继承,交互式 prompt 正常工作
|
|
108
|
+
const child = spawn('npx', skillsArgs, {
|
|
109
|
+
stdio: 'inherit',
|
|
110
|
+
shell: false,
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
child.on('error', (err) => {
|
|
114
|
+
if (err.code === 'ENOENT') {
|
|
115
|
+
console.error(`${c.red}ERROR${c.reset} npx command not found. Please install Node.js.`);
|
|
116
|
+
} else {
|
|
117
|
+
console.error(`${c.red}ERROR${c.reset} Failed to execute skills: ${err.message}`);
|
|
118
|
+
}
|
|
119
|
+
process.exit(1);
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
child.on('exit', (code) => {
|
|
123
|
+
process.exit(code || 0);
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function buildWellKnownUrl(identifier) {
|
|
128
|
+
const cleaned = identifier.replace(/^@/, '');
|
|
129
|
+
const parts = cleaned.split('/');
|
|
130
|
+
if (parts.length === 2) {
|
|
131
|
+
if (!parts[0] || !parts[1]) {
|
|
132
|
+
console.error(`${c.red}ERROR${c.reset} Invalid legacy slug format: ${identifier}`);
|
|
133
|
+
console.log(`${c.bold}Expected:${c.reset} @author/name or skill_info.slug`);
|
|
134
|
+
process.exit(1);
|
|
135
|
+
}
|
|
136
|
+
return `${BASE_URL}/skills/${encodeURIComponent(parts[0])}/${encodeURIComponent(parts[1])}`;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
if (parts.length !== 1 || !/^[A-Za-z0-9_-]+$/.test(cleaned)) {
|
|
140
|
+
console.error(`${c.red}ERROR${c.reset} Invalid skill identifier: ${identifier}`);
|
|
141
|
+
console.log(`${c.bold}Expected:${c.reset} skill_info.slug, skill_id, or legacy @author/name`);
|
|
142
|
+
process.exit(1);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
return `${BASE_URL}/skills/${encodeURIComponent(cleaned)}`;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
main();
|
package/package.json
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "crabhub",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "CrabHub - Skill platform CLI. Delegates to skills package for installation.",
|
|
5
|
+
"bin": {
|
|
6
|
+
"crabhub": "./bin/crabhub.js"
|
|
7
|
+
},
|
|
8
|
+
"files": [
|
|
9
|
+
"bin/crabhub.js"
|
|
10
|
+
],
|
|
11
|
+
"engines": {
|
|
12
|
+
"node": ">=16.0.0"
|
|
13
|
+
},
|
|
14
|
+
"license": "MIT"
|
|
15
|
+
}
|