@botanee/skillhub-cli 1.0.6
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/run +18 -0
- package/dist/commands/agent-login.d.ts +16 -0
- package/dist/commands/agent-login.js +102 -0
- package/dist/commands/config.d.ts +19 -0
- package/dist/commands/config.js +99 -0
- package/dist/commands/help.d.ts +12 -0
- package/dist/commands/help.js +21 -0
- package/dist/commands/install.d.ts +17 -0
- package/dist/commands/install.js +244 -0
- package/dist/commands/list.d.ts +11 -0
- package/dist/commands/list.js +127 -0
- package/dist/commands/login.d.ts +10 -0
- package/dist/commands/login.js +84 -0
- package/dist/commands/logout.d.ts +9 -0
- package/dist/commands/logout.js +25 -0
- package/dist/commands/publish.d.ts +14 -0
- package/dist/commands/publish.js +139 -0
- package/dist/commands/search.d.ts +15 -0
- package/dist/commands/search.js +72 -0
- package/dist/commands/uninstall.d.ts +15 -0
- package/dist/commands/uninstall.js +96 -0
- package/dist/commands/update.d.ts +17 -0
- package/dist/commands/update.js +250 -0
- package/dist/commands/whoami.d.ts +9 -0
- package/dist/commands/whoami.js +42 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.js +138 -0
- package/dist/lib/install-paths.d.ts +20 -0
- package/dist/lib/install-paths.js +77 -0
- package/package.json +46 -0
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
const core_1 = require("@oclif/core");
|
|
40
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
41
|
+
const fs = __importStar(require("fs"));
|
|
42
|
+
const path = __importStar(require("path"));
|
|
43
|
+
const index_1 = require("../index");
|
|
44
|
+
const install_paths_1 = require("../lib/install-paths");
|
|
45
|
+
class List extends index_1.BaseCommand {
|
|
46
|
+
static description = '列出已安装的 Skills';
|
|
47
|
+
static examples = [
|
|
48
|
+
'$ btnskill list',
|
|
49
|
+
'$ btnskill list --agent-type claude-code',
|
|
50
|
+
'$ btnskill list -l',
|
|
51
|
+
];
|
|
52
|
+
static flags = {
|
|
53
|
+
help: core_1.Flags.help({ char: 'h' }),
|
|
54
|
+
'agent-type': core_1.Flags.string({ description: `列出指定 Agent 类型目录下的 Skills,支持 ${install_paths_1.SUPPORTED_INSTALL_AGENT_TYPES.join('/')}` }),
|
|
55
|
+
local: core_1.Flags.boolean({ char: 'l', description: '列出本地安装的 Skills' }),
|
|
56
|
+
};
|
|
57
|
+
async run() {
|
|
58
|
+
const { flags } = await this.parse(List);
|
|
59
|
+
// 确定目录(默认通用 Agent 目录 ~/.agents/skills)
|
|
60
|
+
const resolved = (0, install_paths_1.resolveSkillsDir)({ local: flags.local, agentType: flags['agent-type'] });
|
|
61
|
+
if (resolved.unsupportedAgentType) {
|
|
62
|
+
this.error(`不支持的 Agent 类型: ${resolved.unsupportedAgentType}。当前支持: ${install_paths_1.SUPPORTED_INSTALL_AGENT_TYPES.join(', ')}`);
|
|
63
|
+
}
|
|
64
|
+
const baseDir = resolved.dir;
|
|
65
|
+
if (!fs.existsSync(baseDir)) {
|
|
66
|
+
this.log(chalk_1.default.yellow('没有找到已安装的 Skill'));
|
|
67
|
+
this.log(`安装目录: ${baseDir}`);
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
const skills = fs.readdirSync(baseDir).filter(file => {
|
|
71
|
+
return fs.statSync(path.join(baseDir, file)).isDirectory();
|
|
72
|
+
});
|
|
73
|
+
if (skills.length === 0) {
|
|
74
|
+
this.log(chalk_1.default.yellow('没有找到已安装的 Skill'));
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
const scope = flags.local ? '本地' : (resolved.agentType || '默认');
|
|
78
|
+
this.log(chalk_1.default.blue(`\n已安装的 Skills (${scope}):\n`));
|
|
79
|
+
for (const skillName of skills) {
|
|
80
|
+
const skillDir = path.join(baseDir, skillName);
|
|
81
|
+
const metaPath = path.join(skillDir, '_meta.json');
|
|
82
|
+
const originPath = path.join(skillDir, '.btnskill', 'origin.json');
|
|
83
|
+
let meta = null;
|
|
84
|
+
let origin = null;
|
|
85
|
+
// 读取 _meta.json
|
|
86
|
+
if (fs.existsSync(metaPath)) {
|
|
87
|
+
try {
|
|
88
|
+
meta = JSON.parse(fs.readFileSync(metaPath, 'utf-8'));
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
// 忽略解析错误
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
// 读取 .btnskill/origin.json
|
|
95
|
+
if (fs.existsSync(originPath)) {
|
|
96
|
+
try {
|
|
97
|
+
origin = JSON.parse(fs.readFileSync(originPath, 'utf-8'));
|
|
98
|
+
}
|
|
99
|
+
catch {
|
|
100
|
+
// 忽略解析错误
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
// 显示技能信息
|
|
104
|
+
if (meta) {
|
|
105
|
+
this.log(chalk_1.default.bold(meta.name) + chalk_1.default.gray(` v${meta.version}`));
|
|
106
|
+
if (meta.description) {
|
|
107
|
+
this.log(chalk_1.default.gray(meta.description));
|
|
108
|
+
}
|
|
109
|
+
if (meta.tags && meta.tags.length > 0) {
|
|
110
|
+
this.log(chalk_1.default.cyan(` 标签: ${meta.tags.join(', ')}`));
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
this.log(chalk_1.default.bold(skillName) + chalk_1.default.gray(' (无元数据)'));
|
|
115
|
+
}
|
|
116
|
+
// 显示安装信息
|
|
117
|
+
if (origin) {
|
|
118
|
+
const installedDate = new Date(origin.installedAt).toLocaleString('zh-CN');
|
|
119
|
+
this.log(chalk_1.default.gray(` 安装版本: ${origin.installedVersion}`));
|
|
120
|
+
this.log(chalk_1.default.gray(` 安装时间: ${installedDate}`));
|
|
121
|
+
}
|
|
122
|
+
this.log(chalk_1.default.gray(` 路径: ${skillDir}`));
|
|
123
|
+
this.log();
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
exports.default = List;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { BaseCommand } from '../index';
|
|
2
|
+
export default class Login extends BaseCommand {
|
|
3
|
+
static description: string;
|
|
4
|
+
static examples: string[];
|
|
5
|
+
static flags: {
|
|
6
|
+
help: import("@oclif/core/lib/interfaces").BooleanFlag<void>;
|
|
7
|
+
};
|
|
8
|
+
run(): Promise<void>;
|
|
9
|
+
private waitForCallback;
|
|
10
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const core_1 = require("@oclif/core");
|
|
7
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
8
|
+
const open_1 = __importDefault(require("open"));
|
|
9
|
+
const http_1 = __importDefault(require("http"));
|
|
10
|
+
const url_1 = require("url");
|
|
11
|
+
const index_1 = require("../index");
|
|
12
|
+
class Login extends index_1.BaseCommand {
|
|
13
|
+
static description = '登录 BtnSkillHub 平台';
|
|
14
|
+
static examples = ['$ btnskill login'];
|
|
15
|
+
static flags = {
|
|
16
|
+
help: core_1.Flags.help({ char: 'h' }),
|
|
17
|
+
};
|
|
18
|
+
async run() {
|
|
19
|
+
this.log(chalk_1.default.blue('\n🔐 BtnSkillHub 登录\n'));
|
|
20
|
+
const callbackPort = 18765;
|
|
21
|
+
// 1. 启动本地回调服务器
|
|
22
|
+
const authUrl = `${this.apiBaseUrl}/auth/login?redirect_uri=http://localhost:${callbackPort}/callback`;
|
|
23
|
+
this.log('正在打开浏览器进行飞书授权...');
|
|
24
|
+
this.log(`如果浏览器没有自动打开,请访问:\n${chalk_1.default.cyan(authUrl)}\n`);
|
|
25
|
+
// 2. 等待回调
|
|
26
|
+
const token = await this.waitForCallback(callbackPort);
|
|
27
|
+
// 3. 保存 token
|
|
28
|
+
this.storeAuthSession({
|
|
29
|
+
accessToken: token,
|
|
30
|
+
authMode: 'cli',
|
|
31
|
+
});
|
|
32
|
+
this.log(chalk_1.default.green('\n✅ 登录成功!'));
|
|
33
|
+
this.log('现在可以使用 btnskill 命令了\n');
|
|
34
|
+
}
|
|
35
|
+
waitForCallback(port) {
|
|
36
|
+
return new Promise((resolve, reject) => {
|
|
37
|
+
const server = http_1.default.createServer((req, res) => {
|
|
38
|
+
const url = new url_1.URL(req.url || '/', `http://localhost:${port}`);
|
|
39
|
+
if (url.pathname === '/callback') {
|
|
40
|
+
const token = url.searchParams.get('token');
|
|
41
|
+
const error = url.searchParams.get('error');
|
|
42
|
+
if (token) {
|
|
43
|
+
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
|
|
44
|
+
res.end(`
|
|
45
|
+
<html>
|
|
46
|
+
<body style="display:flex;justify-content:center;align-items:center;height:100vh;font-family:system-ui">
|
|
47
|
+
<div style="text-align:center">
|
|
48
|
+
<h1 style="color:#3B82F6">✅ 登录成功</h1>
|
|
49
|
+
<p>请关闭此页面,回到终端继续操作</p>
|
|
50
|
+
</div>
|
|
51
|
+
</body>
|
|
52
|
+
</html>
|
|
53
|
+
`);
|
|
54
|
+
server.close();
|
|
55
|
+
resolve(token);
|
|
56
|
+
}
|
|
57
|
+
else if (error) {
|
|
58
|
+
res.writeHead(400, { 'Content-Type': 'text/html; charset=utf-8' });
|
|
59
|
+
res.end(`<h1>❌ 登录失败: ${error}</h1>`);
|
|
60
|
+
server.close();
|
|
61
|
+
reject(new Error(error));
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
res.writeHead(404);
|
|
66
|
+
res.end('Not found');
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
server.listen(port, () => {
|
|
70
|
+
// 打开浏览器
|
|
71
|
+
const loginUrl = `${this.apiBaseUrl}/auth/login?redirect_uri=http://localhost:${port}/callback`;
|
|
72
|
+
(0, open_1.default)(loginUrl).catch(() => {
|
|
73
|
+
this.log(chalk_1.default.yellow('无法自动打开浏览器,请手动访问上面的链接'));
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
// 超时处理
|
|
77
|
+
setTimeout(() => {
|
|
78
|
+
server.close();
|
|
79
|
+
reject(new Error('登录超时,请重试'));
|
|
80
|
+
}, 5 * 60 * 1000); // 5 分钟超时
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
exports.default = Login;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { BaseCommand } from '../index';
|
|
2
|
+
export default class Logout extends BaseCommand {
|
|
3
|
+
static description: string;
|
|
4
|
+
static examples: string[];
|
|
5
|
+
static flags: {
|
|
6
|
+
help: import("@oclif/core/lib/interfaces").BooleanFlag<void>;
|
|
7
|
+
};
|
|
8
|
+
run(): Promise<void>;
|
|
9
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const core_1 = require("@oclif/core");
|
|
7
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
8
|
+
const index_1 = require("../index");
|
|
9
|
+
class Logout extends index_1.BaseCommand {
|
|
10
|
+
static description = '登出 BtnSkillHub 平台';
|
|
11
|
+
static examples = ['$ btnskill logout'];
|
|
12
|
+
static flags = {
|
|
13
|
+
help: core_1.Flags.help({ char: 'h' }),
|
|
14
|
+
};
|
|
15
|
+
async run() {
|
|
16
|
+
const token = this.getStoredToken();
|
|
17
|
+
if (!token) {
|
|
18
|
+
this.log(chalk_1.default.yellow('当前未登录'));
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
this.clearStoredAuth();
|
|
22
|
+
this.log(chalk_1.default.green('✅ 已登出'));
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
exports.default = Logout;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { BaseCommand } from '../index';
|
|
2
|
+
export default class Publish extends BaseCommand {
|
|
3
|
+
static description: string;
|
|
4
|
+
static examples: string[];
|
|
5
|
+
static flags: {
|
|
6
|
+
help: import("@oclif/core/lib/interfaces").BooleanFlag<void>;
|
|
7
|
+
private: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
8
|
+
'skip-scan': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
9
|
+
};
|
|
10
|
+
static args: {
|
|
11
|
+
path: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
|
|
12
|
+
};
|
|
13
|
+
run(): Promise<void>;
|
|
14
|
+
}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
const core_1 = require("@oclif/core");
|
|
40
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
41
|
+
const cli_ux_1 = __importDefault(require("cli-ux"));
|
|
42
|
+
const axios_1 = __importDefault(require("axios"));
|
|
43
|
+
const fs = __importStar(require("fs"));
|
|
44
|
+
const path = __importStar(require("path"));
|
|
45
|
+
const os = __importStar(require("os"));
|
|
46
|
+
const adm_zip_1 = __importDefault(require("adm-zip"));
|
|
47
|
+
const index_1 = require("../index");
|
|
48
|
+
class Publish extends index_1.BaseCommand {
|
|
49
|
+
static description = '发布一个 Skill 到平台';
|
|
50
|
+
static examples = [
|
|
51
|
+
'$ btnskill publish',
|
|
52
|
+
'$ btnskill publish ./my-skill',
|
|
53
|
+
'$ btnskill publish ./my-skill --private',
|
|
54
|
+
];
|
|
55
|
+
static flags = {
|
|
56
|
+
help: core_1.Flags.help({ char: 'h' }),
|
|
57
|
+
private: core_1.Flags.boolean({ description: '设为私有 Skill' }),
|
|
58
|
+
'skip-scan': core_1.Flags.boolean({ description: '跳过安全扫描(仅管理员)' }),
|
|
59
|
+
};
|
|
60
|
+
static args = {
|
|
61
|
+
path: core_1.Args.string({ description: 'Skill 目录路径', default: '.' }),
|
|
62
|
+
};
|
|
63
|
+
async run() {
|
|
64
|
+
const { args, flags } = await this.parse(Publish);
|
|
65
|
+
const token = await this.requireAuth();
|
|
66
|
+
const skillPath = path.resolve(args.path);
|
|
67
|
+
const manifestPath = path.join(skillPath, 'skill.json');
|
|
68
|
+
// 检查 skill.json 是否存在
|
|
69
|
+
if (!fs.existsSync(manifestPath)) {
|
|
70
|
+
this.error(`未找到 skill.json 文件: ${manifestPath}`);
|
|
71
|
+
}
|
|
72
|
+
let manifest;
|
|
73
|
+
try {
|
|
74
|
+
manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf-8'));
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
this.error('skill.json 格式无效');
|
|
78
|
+
}
|
|
79
|
+
// 验证必要字段
|
|
80
|
+
if (!manifest.name || !manifest.version || !manifest.description) {
|
|
81
|
+
this.error('skill.json 必须包含 name, version, description 字段');
|
|
82
|
+
}
|
|
83
|
+
cli_ux_1.default.action.start(`正在发布 ${manifest.name}@${manifest.version}`);
|
|
84
|
+
try {
|
|
85
|
+
// 1. 打包 Skill
|
|
86
|
+
const tmpFile = path.join(os.tmpdir(), `${manifest.name}-${Date.now()}.zip`);
|
|
87
|
+
const zip = new adm_zip_1.default();
|
|
88
|
+
zip.addLocalFolder(skillPath);
|
|
89
|
+
zip.writeZip(tmpFile);
|
|
90
|
+
// 2. 读取文件并上传
|
|
91
|
+
const fileBuffer = fs.readFileSync(tmpFile);
|
|
92
|
+
const formData = new FormData();
|
|
93
|
+
formData.append('file', new Blob([fileBuffer]), `${manifest.name}.zip`);
|
|
94
|
+
formData.append('name', manifest.name);
|
|
95
|
+
formData.append('version', manifest.version);
|
|
96
|
+
formData.append('description', manifest.description);
|
|
97
|
+
formData.append('isPublic', (!flags.private).toString());
|
|
98
|
+
if (manifest.tags) {
|
|
99
|
+
formData.append('tags', JSON.stringify(manifest.tags));
|
|
100
|
+
}
|
|
101
|
+
if (flags['skip-scan']) {
|
|
102
|
+
formData.append('skipScan', 'true');
|
|
103
|
+
}
|
|
104
|
+
const response = await axios_1.default.post(`${this.apiBaseUrl}/skills`, formData, {
|
|
105
|
+
headers: {
|
|
106
|
+
Authorization: `Bearer ${token}`,
|
|
107
|
+
'Content-Type': 'multipart/form-data',
|
|
108
|
+
},
|
|
109
|
+
});
|
|
110
|
+
// 3. 清理临时文件
|
|
111
|
+
fs.unlinkSync(tmpFile);
|
|
112
|
+
cli_ux_1.default.action.stop();
|
|
113
|
+
const skill = response.data.data;
|
|
114
|
+
this.log(chalk_1.default.green(`\n✅ 成功发布 ${skill.name}@${skill.version}`));
|
|
115
|
+
this.log(`Skill ID: ${skill.id}`);
|
|
116
|
+
if (flags['skip-scan']) {
|
|
117
|
+
this.log(chalk_1.default.yellow('⚠️ 已跳过安全扫描'));
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
this.log(chalk_1.default.gray('安全扫描将在后台运行,结果将通过通知发送'));
|
|
121
|
+
}
|
|
122
|
+
this.log();
|
|
123
|
+
}
|
|
124
|
+
catch (error) {
|
|
125
|
+
cli_ux_1.default.action.stop('失败');
|
|
126
|
+
if (error.response?.status === 401) {
|
|
127
|
+
this.error(`登录已过期,请重新登录: ${this.loginHint}`);
|
|
128
|
+
}
|
|
129
|
+
if (error.response?.status === 409) {
|
|
130
|
+
this.error('该版本已存在,请更新版本号');
|
|
131
|
+
}
|
|
132
|
+
if (error.response?.status === 403) {
|
|
133
|
+
this.error('无发布权限,请联系管理员');
|
|
134
|
+
}
|
|
135
|
+
this.error(error.response?.data?.message || '发布失败');
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
exports.default = Publish;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { BaseCommand } from '../index';
|
|
2
|
+
export default class Search extends BaseCommand {
|
|
3
|
+
static description: string;
|
|
4
|
+
static examples: string[];
|
|
5
|
+
static flags: {
|
|
6
|
+
help: import("@oclif/core/lib/interfaces").BooleanFlag<void>;
|
|
7
|
+
tag: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
8
|
+
page: import("@oclif/core/lib/interfaces").OptionFlag<number, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
9
|
+
limit: import("@oclif/core/lib/interfaces").OptionFlag<number, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
10
|
+
};
|
|
11
|
+
static args: {
|
|
12
|
+
query: import("@oclif/core/lib/interfaces").Arg<string | undefined, Record<string, unknown>>;
|
|
13
|
+
};
|
|
14
|
+
run(): Promise<void>;
|
|
15
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const core_1 = require("@oclif/core");
|
|
7
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
8
|
+
const cli_ux_1 = __importDefault(require("cli-ux"));
|
|
9
|
+
const axios_1 = __importDefault(require("axios"));
|
|
10
|
+
const index_1 = require("../index");
|
|
11
|
+
class Search extends index_1.BaseCommand {
|
|
12
|
+
static description = '搜索可用的 Skills';
|
|
13
|
+
static examples = [
|
|
14
|
+
'$ btnskill search',
|
|
15
|
+
'$ btnskill search claude',
|
|
16
|
+
'$ btnskill search --tag productivity',
|
|
17
|
+
];
|
|
18
|
+
static flags = {
|
|
19
|
+
help: core_1.Flags.help({ char: 'h' }),
|
|
20
|
+
tag: core_1.Flags.string({ description: '按标签搜索' }),
|
|
21
|
+
page: core_1.Flags.integer({ description: '页码', default: 1 }),
|
|
22
|
+
limit: core_1.Flags.integer({ description: '每页数量', default: 20 }),
|
|
23
|
+
};
|
|
24
|
+
static args = {
|
|
25
|
+
query: core_1.Args.string({ description: '搜索关键词(按名称)' }),
|
|
26
|
+
};
|
|
27
|
+
async run() {
|
|
28
|
+
const { flags, args } = await this.parse(Search);
|
|
29
|
+
const token = await this.requireAuth();
|
|
30
|
+
cli_ux_1.default.action.start('正在搜索');
|
|
31
|
+
try {
|
|
32
|
+
const params = new URLSearchParams();
|
|
33
|
+
if (args.query)
|
|
34
|
+
params.append('name', args.query);
|
|
35
|
+
if (flags.tag)
|
|
36
|
+
params.append('tag', flags.tag);
|
|
37
|
+
params.append('page', flags.page.toString());
|
|
38
|
+
params.append('limit', flags.limit.toString());
|
|
39
|
+
const response = await axios_1.default.get(`${this.apiBaseUrl}/skills?${params.toString()}`, {
|
|
40
|
+
headers: { Authorization: `Bearer ${token}` },
|
|
41
|
+
});
|
|
42
|
+
cli_ux_1.default.action.stop();
|
|
43
|
+
const { skills, total } = response.data.data;
|
|
44
|
+
if (skills.length === 0) {
|
|
45
|
+
this.log(chalk_1.default.yellow('没有找到匹配的 Skill'));
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
this.log(chalk_1.default.blue(`\n找到 ${total} 个 Skill:\n`));
|
|
49
|
+
for (const rawSkill of skills) {
|
|
50
|
+
const tags = Array.isArray(rawSkill.tags) ? rawSkill.tags.filter(tag => typeof tag === 'string') : [];
|
|
51
|
+
const name = rawSkill.name || '未命名 Skill';
|
|
52
|
+
const version = rawSkill.version || 'unknown';
|
|
53
|
+
const description = rawSkill.description || '暂无描述';
|
|
54
|
+
const downloadCount = rawSkill.downloadCount ?? 0;
|
|
55
|
+
const rating = rawSkill.rating ?? '暂无';
|
|
56
|
+
this.log(chalk_1.default.bold(name) + chalk_1.default.gray(` v${version}`));
|
|
57
|
+
this.log(chalk_1.default.gray(description));
|
|
58
|
+
this.log(chalk_1.default.cyan(` 标签: ${tags.length > 0 ? tags.join(', ') : '无'}`));
|
|
59
|
+
this.log(chalk_1.default.gray(` 下载: ${downloadCount} | 评分: ${rating}`));
|
|
60
|
+
this.log();
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
catch (error) {
|
|
64
|
+
cli_ux_1.default.action.stop('失败');
|
|
65
|
+
if (error.response?.status === 401) {
|
|
66
|
+
this.error(`登录已过期,请重新登录: ${this.loginHint}`);
|
|
67
|
+
}
|
|
68
|
+
this.error(error.response?.data?.message || '搜索失败');
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
exports.default = Search;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { BaseCommand } from '../index';
|
|
2
|
+
export default class Uninstall extends BaseCommand {
|
|
3
|
+
static description: string;
|
|
4
|
+
static examples: string[];
|
|
5
|
+
static flags: {
|
|
6
|
+
help: import("@oclif/core/lib/interfaces").BooleanFlag<void>;
|
|
7
|
+
'agent-type': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
8
|
+
local: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
9
|
+
force: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
10
|
+
};
|
|
11
|
+
static args: {
|
|
12
|
+
skill: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
|
|
13
|
+
};
|
|
14
|
+
run(): Promise<void>;
|
|
15
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
const core_1 = require("@oclif/core");
|
|
40
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
41
|
+
const fs = __importStar(require("fs"));
|
|
42
|
+
const path = __importStar(require("path"));
|
|
43
|
+
const inquirer_1 = __importDefault(require("inquirer"));
|
|
44
|
+
const index_1 = require("../index");
|
|
45
|
+
const install_paths_1 = require("../lib/install-paths");
|
|
46
|
+
class Uninstall extends index_1.BaseCommand {
|
|
47
|
+
static description = '卸载已安装的 Skill';
|
|
48
|
+
static examples = [
|
|
49
|
+
'$ btnskill uninstall my-skill',
|
|
50
|
+
'$ btnskill uninstall my-skill --agent-type claude-code',
|
|
51
|
+
'$ btnskill uninstall my-skill -f',
|
|
52
|
+
];
|
|
53
|
+
static flags = {
|
|
54
|
+
help: core_1.Flags.help({ char: 'h' }),
|
|
55
|
+
'agent-type': core_1.Flags.string({ description: `卸载指定 Agent 类型目录下的 Skill,支持 ${install_paths_1.SUPPORTED_INSTALL_AGENT_TYPES.join('/')}` }),
|
|
56
|
+
local: core_1.Flags.boolean({ char: 'l', description: '卸载本地安装的 Skill' }),
|
|
57
|
+
force: core_1.Flags.boolean({ char: 'f', description: '强制卸载,不询问确认' }),
|
|
58
|
+
};
|
|
59
|
+
static args = {
|
|
60
|
+
skill: core_1.Args.string({ description: 'Skill 名称', required: true }),
|
|
61
|
+
};
|
|
62
|
+
async run() {
|
|
63
|
+
const { args, flags } = await this.parse(Uninstall);
|
|
64
|
+
const skillName = args.skill;
|
|
65
|
+
// 默认通用 Agent 目录 ~/.agents/skills
|
|
66
|
+
const resolved = (0, install_paths_1.resolveSkillsDir)({ local: flags.local, agentType: flags['agent-type'] });
|
|
67
|
+
if (resolved.unsupportedAgentType) {
|
|
68
|
+
this.error(`不支持的 Agent 类型: ${resolved.unsupportedAgentType}。当前支持: ${install_paths_1.SUPPORTED_INSTALL_AGENT_TYPES.join(', ')}`);
|
|
69
|
+
}
|
|
70
|
+
const baseDir = resolved.dir;
|
|
71
|
+
const skillDir = path.join(baseDir, skillName);
|
|
72
|
+
// 检查 Skill 是否存在
|
|
73
|
+
if (!fs.existsSync(skillDir)) {
|
|
74
|
+
this.error(`未找到 Skill: ${skillName}`);
|
|
75
|
+
}
|
|
76
|
+
// 确认卸载
|
|
77
|
+
if (!flags.force) {
|
|
78
|
+
const { confirm } = await inquirer_1.default.prompt([
|
|
79
|
+
{
|
|
80
|
+
type: 'confirm',
|
|
81
|
+
name: 'confirm',
|
|
82
|
+
message: `确定要卸载 ${skillName} 吗?`,
|
|
83
|
+
default: false,
|
|
84
|
+
},
|
|
85
|
+
]);
|
|
86
|
+
if (!confirm) {
|
|
87
|
+
this.log(chalk_1.default.yellow('已取消'));
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
// 删除目录
|
|
92
|
+
fs.rmSync(skillDir, { recursive: true });
|
|
93
|
+
this.log(chalk_1.default.green(`✅ 已卸载 ${skillName}`));
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
exports.default = Uninstall;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { BaseCommand } from '../index';
|
|
2
|
+
export default class Update extends BaseCommand {
|
|
3
|
+
static description: string;
|
|
4
|
+
static examples: string[];
|
|
5
|
+
static flags: {
|
|
6
|
+
help: import("@oclif/core/lib/interfaces").BooleanFlag<void>;
|
|
7
|
+
'agent-type': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
8
|
+
local: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
9
|
+
check: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
10
|
+
};
|
|
11
|
+
static args: {
|
|
12
|
+
skill: import("@oclif/core/lib/interfaces").Arg<string | undefined, Record<string, unknown>>;
|
|
13
|
+
};
|
|
14
|
+
run(): Promise<void>;
|
|
15
|
+
private updateSkill;
|
|
16
|
+
private getInstalledSkills;
|
|
17
|
+
}
|