@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.
@@ -0,0 +1,250 @@
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
+ const install_paths_1 = require("../lib/install-paths");
49
+ class Update extends index_1.BaseCommand {
50
+ static description = '更新已安装的 Skill';
51
+ static examples = [
52
+ '$ btnskill update',
53
+ '$ btnskill update my-skill',
54
+ '$ btnskill update my-skill --agent-type claude-code',
55
+ ];
56
+ static flags = {
57
+ help: core_1.Flags.help({ char: 'h' }),
58
+ 'agent-type': core_1.Flags.string({ description: `更新指定 Agent 类型目录下的 Skills,支持 ${install_paths_1.SUPPORTED_INSTALL_AGENT_TYPES.join('/')}` }),
59
+ local: core_1.Flags.boolean({ char: 'l', description: '更新本地安装的 Skills' }),
60
+ check: core_1.Flags.boolean({ char: 'c', description: '仅检查更新,不实际更新' }),
61
+ };
62
+ static args = {
63
+ skill: core_1.Args.string({ description: '要更新的 Skill 名称(不指定则更新所有)' }),
64
+ };
65
+ async run() {
66
+ const { args, flags } = await this.parse(Update);
67
+ const token = await this.requireAuth();
68
+ const isCheckOnly = flags.check;
69
+ // 默认通用 Agent 目录 ~/.agents/skills
70
+ const resolved = (0, install_paths_1.resolveSkillsDir)({ local: flags.local, agentType: flags['agent-type'] });
71
+ if (resolved.unsupportedAgentType) {
72
+ this.error(`不支持的 Agent 类型: ${resolved.unsupportedAgentType}。当前支持: ${install_paths_1.SUPPORTED_INSTALL_AGENT_TYPES.join(', ')}`);
73
+ }
74
+ const baseDir = resolved.dir;
75
+ if (!fs.existsSync(baseDir)) {
76
+ this.log(chalk_1.default.yellow('没有找到已安装的 Skill'));
77
+ return;
78
+ }
79
+ // 获取所有已安装的技能及其来源信息
80
+ const installedSkills = this.getInstalledSkills(baseDir);
81
+ if (installedSkills.length === 0) {
82
+ this.log(chalk_1.default.yellow('没有找到已安装的 Skill'));
83
+ return;
84
+ }
85
+ // 确定要更新的技能
86
+ let skillsToCheck = [];
87
+ if (args.skill) {
88
+ const found = installedSkills.find(s => s.name === args.skill);
89
+ if (found) {
90
+ skillsToCheck = [found];
91
+ }
92
+ else {
93
+ this.error(`未找到 Skill: ${args.skill}`);
94
+ }
95
+ }
96
+ else {
97
+ skillsToCheck = installedSkills;
98
+ }
99
+ // 检查更新
100
+ this.log(chalk_1.default.blue('\n正在检查更新...\n'));
101
+ const updatesAvailable = [];
102
+ const upToDate = [];
103
+ const failed = [];
104
+ for (const { name, origin } of skillsToCheck) {
105
+ try {
106
+ const response = await axios_1.default.get(`${this.apiBaseUrl}/skills/${encodeURIComponent(origin.id || name)}`, { headers: { Authorization: `Bearer ${token}` } });
107
+ const skill = response.data.data;
108
+ const currentVersion = origin.installedVersion || 'unknown';
109
+ if (skill.version !== currentVersion) {
110
+ updatesAvailable.push({
111
+ name,
112
+ currentVersion,
113
+ latestVersion: skill.version,
114
+ skill,
115
+ });
116
+ }
117
+ else {
118
+ upToDate.push(name);
119
+ }
120
+ }
121
+ catch {
122
+ failed.push(name);
123
+ }
124
+ }
125
+ // 显示结果
126
+ if (upToDate.length > 0) {
127
+ for (const name of upToDate) {
128
+ this.log(chalk_1.default.gray(` ✓ ${name} 已是最新版本`));
129
+ }
130
+ }
131
+ if (failed.length > 0) {
132
+ for (const name of failed) {
133
+ this.log(chalk_1.default.red(` ✗ ${name} 检查失败`));
134
+ }
135
+ }
136
+ if (updatesAvailable.length > 0) {
137
+ this.log(chalk_1.default.green('\n有新版本可用:'));
138
+ for (const { name, currentVersion, latestVersion } of updatesAvailable) {
139
+ this.log(chalk_1.default.green(` ↑ ${name}: ${currentVersion} → ${latestVersion}`));
140
+ }
141
+ this.log();
142
+ if (isCheckOnly) {
143
+ this.log(chalk_1.default.yellow('使用 --check 模式,仅显示更新信息\n'));
144
+ return;
145
+ }
146
+ // 自动更新
147
+ for (const { name, skill } of updatesAvailable) {
148
+ cli_ux_1.default.action.start(`正在更新 ${name}`);
149
+ try {
150
+ await this.updateSkill(name, skill, baseDir, token);
151
+ cli_ux_1.default.action.stop();
152
+ this.log(chalk_1.default.green(` ✅ ${name} 更新成功`));
153
+ }
154
+ catch {
155
+ cli_ux_1.default.action.stop('失败');
156
+ this.log(chalk_1.default.red(` ❌ ${name} 更新失败`));
157
+ }
158
+ }
159
+ }
160
+ else {
161
+ this.log(chalk_1.default.green('\n所有 Skill 都是最新版本'));
162
+ }
163
+ this.log();
164
+ }
165
+ async updateSkill(name, skill, baseDir, token) {
166
+ const fileResponse = await axios_1.default.get(`${this.apiBaseUrl}/skills/${skill.id}/download`, {
167
+ headers: { Authorization: `Bearer ${token}` },
168
+ responseType: 'arraybuffer',
169
+ });
170
+ const skillDir = path.join(baseDir, name);
171
+ const tmpFile = path.join(os.tmpdir(), `${name}-${Date.now()}.zip`);
172
+ fs.writeFileSync(tmpFile, fileResponse.data);
173
+ // 删除旧版本
174
+ if (fs.existsSync(skillDir)) {
175
+ fs.rmSync(skillDir, { recursive: true });
176
+ }
177
+ // 解压到临时目录
178
+ const extractDir = path.join(os.tmpdir(), `extract-${Date.now()}`);
179
+ const zip = new adm_zip_1.default(tmpFile);
180
+ zip.extractAllTo(extractDir, true);
181
+ // 检查是否需要"提升"目录
182
+ const extractedItems = fs.readdirSync(extractDir);
183
+ let sourceDir = extractDir;
184
+ const validItems = extractedItems.filter(item => !item.startsWith('.') && !item.startsWith('__MACOSX'));
185
+ if (validItems.length === 1 && !validItems[0].includes('.')) {
186
+ sourceDir = path.join(extractDir, validItems[0]);
187
+ }
188
+ // 移动到最终目录
189
+ fs.mkdirSync(skillDir, { recursive: true });
190
+ const items = fs.readdirSync(sourceDir);
191
+ for (const item of items) {
192
+ if (item.startsWith('__MACOSX'))
193
+ continue;
194
+ fs.renameSync(path.join(sourceDir, item), path.join(skillDir, item));
195
+ }
196
+ // 清理临时目录
197
+ fs.rmSync(extractDir, { recursive: true });
198
+ // 生成元数据文件
199
+ const metaData = {
200
+ name: skill.name,
201
+ version: skill.version,
202
+ description: skill.description,
203
+ author: skill.authorId,
204
+ tags: skill.tags || [],
205
+ publishedAt: skill.createdAt,
206
+ };
207
+ fs.writeFileSync(path.join(skillDir, '_meta.json'), JSON.stringify(metaData, null, 2));
208
+ const btnskillDir = path.join(skillDir, '.btnskill');
209
+ if (!fs.existsSync(btnskillDir)) {
210
+ fs.mkdirSync(btnskillDir, { recursive: true });
211
+ }
212
+ const originData = {
213
+ version: 1,
214
+ registry: this.registryOrigin,
215
+ name: skill.name,
216
+ id: skill.id,
217
+ installedVersion: skill.version,
218
+ installedAt: Date.now(),
219
+ };
220
+ fs.writeFileSync(path.join(btnskillDir, 'origin.json'), JSON.stringify(originData, null, 2));
221
+ // 清理临时文件
222
+ fs.unlinkSync(tmpFile);
223
+ }
224
+ getInstalledSkills(baseDir) {
225
+ const skills = [];
226
+ const skillDirs = fs.readdirSync(baseDir).filter(file => {
227
+ return fs.statSync(path.join(baseDir, file)).isDirectory();
228
+ });
229
+ for (const skillName of skillDirs) {
230
+ const originPath = path.join(baseDir, skillName, '.btnskill', 'origin.json');
231
+ if (fs.existsSync(originPath)) {
232
+ try {
233
+ const origin = JSON.parse(fs.readFileSync(originPath, 'utf-8'));
234
+ skills.push({ name: skillName, origin });
235
+ }
236
+ catch {
237
+ // 忽略
238
+ }
239
+ }
240
+ else {
241
+ skills.push({
242
+ name: skillName,
243
+ origin: { version: 1, registry: '', name: skillName, id: skillName, installedVersion: 'unknown', installedAt: 0 },
244
+ });
245
+ }
246
+ }
247
+ return skills;
248
+ }
249
+ }
250
+ exports.default = Update;
@@ -0,0 +1,9 @@
1
+ import { BaseCommand } from '../index';
2
+ export default class Whoami 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,42 @@
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 Whoami extends index_1.BaseCommand {
12
+ static description = '显示当前登录用户信息';
13
+ static examples = ['$ btnskill whoami'];
14
+ static flags = {
15
+ help: core_1.Flags.help({ char: 'h' }),
16
+ };
17
+ async run() {
18
+ const token = await this.requireAuth();
19
+ cli_ux_1.default.action.start('正在获取用户信息');
20
+ try {
21
+ const response = await axios_1.default.get(`${this.apiBaseUrl}/auth/me`, {
22
+ headers: { Authorization: `Bearer ${token}` },
23
+ });
24
+ cli_ux_1.default.action.stop();
25
+ const user = response.data.data;
26
+ this.log(chalk_1.default.blue('\n当前登录用户:\n'));
27
+ this.log(` 用户名: ${chalk_1.default.bold(user.name)}`);
28
+ this.log(` 邮箱: ${user.email}`);
29
+ this.log(` 角色: ${user.role}`);
30
+ this.log(` 部门: ${user.department || '未设置'}`);
31
+ this.log();
32
+ }
33
+ catch (error) {
34
+ cli_ux_1.default.action.stop('失败');
35
+ if (error.response?.status === 401) {
36
+ this.error(`登录已过期,请重新登录: ${this.loginHint}`);
37
+ }
38
+ this.error(error.response?.data?.message || '获取用户信息失败');
39
+ }
40
+ }
41
+ }
42
+ exports.default = Whoami;
@@ -0,0 +1,24 @@
1
+ import { Command } from '@oclif/core';
2
+ export declare abstract class BaseCommand extends Command {
3
+ protected get envToken(): string | undefined;
4
+ protected get loginHint(): string;
5
+ protected normalizeApiBaseUrl(value?: string): string;
6
+ protected get apiBaseUrl(): string;
7
+ protected get registryOrigin(): string;
8
+ protected getConfigValue(key: string): string | undefined;
9
+ protected setConfigValue(key: string, value: string): void;
10
+ protected deleteConfigValue(key: string): void;
11
+ protected clearStoredAuth(): void;
12
+ protected storeAuthSession(session: {
13
+ accessToken: string;
14
+ refreshToken?: string;
15
+ agentId?: string;
16
+ authMode: 'cli' | 'agent';
17
+ agentType?: string;
18
+ }): void;
19
+ protected getStoredToken(): string | undefined;
20
+ protected requireAuth(): Promise<string>;
21
+ private shouldRefreshToken;
22
+ private tryRefreshAgentToken;
23
+ }
24
+ export { run } from '@oclif/core';
package/dist/index.js ADDED
@@ -0,0 +1,138 @@
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
+ exports.run = exports.BaseCommand = void 0;
7
+ const core_1 = require("@oclif/core");
8
+ const configstore_1 = __importDefault(require("configstore"));
9
+ const axios_1 = __importDefault(require("axios"));
10
+ // 全局配置存储
11
+ const configStore = new configstore_1.default('btnskill');
12
+ const DEFAULT_API_BASE_URL = 'https://skillhub.botanee.com.cn/api/v1';
13
+ class BaseCommand extends core_1.Command {
14
+ get envToken() {
15
+ return process.env.BTNSKILL_TOKEN;
16
+ }
17
+ get loginHint() {
18
+ return 'btnskill login 或 btnskill agent-login';
19
+ }
20
+ normalizeApiBaseUrl(value) {
21
+ const trimmed = (value || DEFAULT_API_BASE_URL).trim().replace(/\/+$/, '');
22
+ return trimmed.endsWith('/api/v1') ? trimmed : `${trimmed}/api/v1`;
23
+ }
24
+ get apiBaseUrl() {
25
+ return this.normalizeApiBaseUrl(process.env.API_BASE_URL || this.getConfigValue('registry') || DEFAULT_API_BASE_URL);
26
+ }
27
+ get registryOrigin() {
28
+ return this.apiBaseUrl.replace(/\/api\/v1$/, '');
29
+ }
30
+ // 获取配置值
31
+ getConfigValue(key) {
32
+ return configStore.get(key);
33
+ }
34
+ // 设置配置值
35
+ setConfigValue(key, value) {
36
+ configStore.set(key, value);
37
+ }
38
+ // 删除配置值
39
+ deleteConfigValue(key) {
40
+ configStore.delete(key);
41
+ }
42
+ clearStoredAuth() {
43
+ this.deleteConfigValue('token');
44
+ this.deleteConfigValue('refreshToken');
45
+ this.deleteConfigValue('agentId');
46
+ this.deleteConfigValue('authMode');
47
+ this.deleteConfigValue('agentType');
48
+ }
49
+ storeAuthSession(session) {
50
+ this.setConfigValue('token', session.accessToken);
51
+ this.setConfigValue('authMode', session.authMode);
52
+ if (session.refreshToken) {
53
+ this.setConfigValue('refreshToken', session.refreshToken);
54
+ }
55
+ else {
56
+ this.deleteConfigValue('refreshToken');
57
+ }
58
+ if (session.agentId) {
59
+ this.setConfigValue('agentId', session.agentId);
60
+ }
61
+ else {
62
+ this.deleteConfigValue('agentId');
63
+ }
64
+ if (session.agentType) {
65
+ this.setConfigValue('agentType', session.agentType);
66
+ }
67
+ else {
68
+ this.deleteConfigValue('agentType');
69
+ }
70
+ }
71
+ getStoredToken() {
72
+ return this.envToken || this.getConfigValue('token');
73
+ }
74
+ // 检查是否已登录
75
+ async requireAuth() {
76
+ const token = this.getStoredToken();
77
+ if (!token) {
78
+ this.error(`请先登录: ${this.loginHint}`, { exit: 1 });
79
+ }
80
+ if (!this.envToken && this.shouldRefreshToken(token)) {
81
+ const refreshedToken = await this.tryRefreshAgentToken();
82
+ if (refreshedToken) {
83
+ return refreshedToken;
84
+ }
85
+ }
86
+ return token;
87
+ }
88
+ shouldRefreshToken(token) {
89
+ if (this.getConfigValue('authMode') !== 'agent') {
90
+ return false;
91
+ }
92
+ const refreshToken = this.getConfigValue('refreshToken');
93
+ const agentId = this.getConfigValue('agentId');
94
+ if (!refreshToken || !agentId) {
95
+ return false;
96
+ }
97
+ try {
98
+ const payload = JSON.parse(Buffer.from(token.split('.')[1], 'base64url').toString('utf8'));
99
+ const expiresAt = payload?.exp ? payload.exp * 1000 : 0;
100
+ return expiresAt > 0 && expiresAt - Date.now() <= 60 * 1000;
101
+ }
102
+ catch {
103
+ return false;
104
+ }
105
+ }
106
+ async tryRefreshAgentToken() {
107
+ const refreshToken = this.getConfigValue('refreshToken');
108
+ const agentId = this.getConfigValue('agentId');
109
+ if (!refreshToken || !agentId) {
110
+ return null;
111
+ }
112
+ try {
113
+ const response = await axios_1.default.post(`${this.apiBaseUrl}/auth/agent/refresh`, {
114
+ refreshToken,
115
+ agentId,
116
+ });
117
+ const data = response.data?.data;
118
+ if (!data?.accessToken) {
119
+ return null;
120
+ }
121
+ this.storeAuthSession({
122
+ accessToken: data.accessToken,
123
+ refreshToken: data.refreshToken || refreshToken,
124
+ agentId,
125
+ authMode: 'agent',
126
+ agentType: this.getConfigValue('agentType') || 'openclaw',
127
+ });
128
+ return data.accessToken;
129
+ }
130
+ catch {
131
+ return null;
132
+ }
133
+ }
134
+ }
135
+ exports.BaseCommand = BaseCommand;
136
+ // oclif 入口
137
+ var core_2 = require("@oclif/core");
138
+ Object.defineProperty(exports, "run", { enumerable: true, get: function () { return core_2.run; } });
@@ -0,0 +1,20 @@
1
+ export declare const DEFAULT_SKILLS_DIR: string;
2
+ export declare const AGENT_TYPE_SKILLS_DIRS: {
3
+ readonly codex: string;
4
+ readonly 'claude-code': string;
5
+ readonly openclaw: string;
6
+ };
7
+ export type InstallAgentType = keyof typeof AGENT_TYPE_SKILLS_DIRS;
8
+ export declare const SUPPORTED_INSTALL_AGENT_TYPES: readonly ["openclaw", "claude-code", "codex"];
9
+ interface ResolveSkillsDirOptions {
10
+ agentType?: string;
11
+ local?: boolean;
12
+ target?: string;
13
+ }
14
+ interface ResolvedSkillsDir {
15
+ agentType?: InstallAgentType;
16
+ dir: string;
17
+ unsupportedAgentType?: string;
18
+ }
19
+ export declare function resolveSkillsDir(options?: ResolveSkillsDirOptions): ResolvedSkillsDir;
20
+ export {};
@@ -0,0 +1,77 @@
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
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.SUPPORTED_INSTALL_AGENT_TYPES = exports.AGENT_TYPE_SKILLS_DIRS = exports.DEFAULT_SKILLS_DIR = void 0;
37
+ exports.resolveSkillsDir = resolveSkillsDir;
38
+ const os = __importStar(require("os"));
39
+ const path = __importStar(require("path"));
40
+ exports.DEFAULT_SKILLS_DIR = path.join(os.homedir(), '.agents', 'skills');
41
+ exports.AGENT_TYPE_SKILLS_DIRS = {
42
+ codex: path.join(os.homedir(), '.codex', 'skills'),
43
+ 'claude-code': path.join(os.homedir(), '.claude', 'skills'),
44
+ openclaw: path.join(os.homedir(), '.openclaw', 'skills'),
45
+ };
46
+ exports.SUPPORTED_INSTALL_AGENT_TYPES = ['openclaw', 'claude-code', 'codex'];
47
+ function resolveSkillsDir(options = {}) {
48
+ if (options.target) {
49
+ return { dir: expandHomeDir(options.target) };
50
+ }
51
+ if (options.local) {
52
+ return { dir: path.join(process.cwd(), '.btnskill', 'skills') };
53
+ }
54
+ if (!options.agentType) {
55
+ return { dir: exports.DEFAULT_SKILLS_DIR };
56
+ }
57
+ const agentType = options.agentType.toLowerCase();
58
+ if (isInstallAgentType(agentType)) {
59
+ return { agentType, dir: exports.AGENT_TYPE_SKILLS_DIRS[agentType] };
60
+ }
61
+ return {
62
+ dir: exports.DEFAULT_SKILLS_DIR,
63
+ unsupportedAgentType: options.agentType,
64
+ };
65
+ }
66
+ function isInstallAgentType(agentType) {
67
+ return Object.prototype.hasOwnProperty.call(exports.AGENT_TYPE_SKILLS_DIRS, agentType);
68
+ }
69
+ function expandHomeDir(target) {
70
+ if (target === '~') {
71
+ return os.homedir();
72
+ }
73
+ if (target.startsWith(`~${path.sep}`)) {
74
+ return path.join(os.homedir(), target.slice(2));
75
+ }
76
+ return target;
77
+ }
package/package.json ADDED
@@ -0,0 +1,46 @@
1
+ {
2
+ "name": "@botanee/skillhub-cli",
3
+ "version": "1.0.6",
4
+ "description": "BtnSkillHub CLI 工具",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "bin": {
8
+ "btnskill": "./bin/run"
9
+ },
10
+ "scripts": {
11
+ "build": "node -e \"require('node:fs').rmSync('dist', { recursive: true, force: true })\" && tsc",
12
+ "dev": "node ./scripts/dev.js",
13
+ "lint": "tsc --noEmit",
14
+ "publish:gitlab": "pnpm build && node ./scripts/publish-gitlab.js"
15
+ },
16
+ "dependencies": {
17
+ "@oclif/core": "^3.0.0",
18
+ "@oclif/plugin-help": "^6.0.0",
19
+ "adm-zip": "^0.5.16",
20
+ "axios": "^1.6.0",
21
+ "chalk": "^4.1.2",
22
+ "cli-ux": "^6.0.9",
23
+ "configstore": "^5.0.1",
24
+ "inquirer": "^8.2.0",
25
+ "open": "^8.4.0",
26
+ "ora": "^5.4.0",
27
+ "qrcode-terminal": "^0.12.0"
28
+ },
29
+ "devDependencies": {
30
+ "@oclif/test": "^3.0.0",
31
+ "@types/adm-zip": "^0.5.8",
32
+ "@types/configstore": "^6.0.0",
33
+ "@types/inquirer": "^8.2.0",
34
+ "@types/node": "^20.0.0",
35
+ "ts-node": "^10.9.0",
36
+ "typescript": "^5.1.0"
37
+ },
38
+ "oclif": {
39
+ "bin": "btnskill",
40
+ "commands": "./dist/commands"
41
+ },
42
+ "files": [
43
+ "/bin",
44
+ "/dist"
45
+ ]
46
+ }