@zhin.js/cli 1.0.7 → 1.0.8

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,151 @@
1
+ import { Command } from 'commander';
2
+ import { logger } from '../utils/logger.js';
3
+ import fs from 'fs-extra';
4
+ import path from 'path';
5
+ import inquirer from 'inquirer';
6
+ import { execSync } from 'node:child_process';
7
+ export const pubCommand = new Command('pub')
8
+ .description('发布插件到 npm')
9
+ .argument('[plugin-name]', '插件名称(如: my-plugin)')
10
+ .option('--tag <tag>', '发布标签', 'latest')
11
+ .option('--access <access>', '访问级别 (public|restricted)', 'public')
12
+ .option('--registry <url>', '自定义 npm registry')
13
+ .option('--dry-run', '试运行,不实际发布', false)
14
+ .option('--skip-build', '跳过构建步骤', false)
15
+ .action(async (pluginName, options) => {
16
+ try {
17
+ const pluginsDir = path.resolve(process.cwd(), 'plugins');
18
+ // 检查 plugins 目录是否存在
19
+ if (!fs.existsSync(pluginsDir)) {
20
+ logger.error('未找到 plugins 目录,请在项目根目录运行此命令');
21
+ process.exit(1);
22
+ }
23
+ // 获取所有插件
24
+ const availablePlugins = fs.readdirSync(pluginsDir)
25
+ .filter(name => {
26
+ const pluginPath = path.join(pluginsDir, name);
27
+ return fs.statSync(pluginPath).isDirectory() &&
28
+ fs.existsSync(path.join(pluginPath, 'package.json'));
29
+ });
30
+ if (availablePlugins.length === 0) {
31
+ logger.error('未找到可发布的插件');
32
+ process.exit(1);
33
+ }
34
+ // 如果没有指定插件名,让用户选择
35
+ let selectedPlugin = pluginName;
36
+ if (!selectedPlugin) {
37
+ if (availablePlugins.length === 1) {
38
+ selectedPlugin = availablePlugins[0];
39
+ logger.info(`自动选择插件: ${selectedPlugin}`);
40
+ }
41
+ else {
42
+ const { plugin } = await inquirer.prompt([
43
+ {
44
+ type: 'list',
45
+ name: 'plugin',
46
+ message: '请选择要发布的插件:',
47
+ choices: availablePlugins
48
+ }
49
+ ]);
50
+ selectedPlugin = plugin;
51
+ }
52
+ }
53
+ // 验证插件是否存在
54
+ const pluginDir = path.join(pluginsDir, selectedPlugin);
55
+ if (!fs.existsSync(pluginDir)) {
56
+ logger.error(`插件不存在: ${selectedPlugin}`);
57
+ logger.log(`可用插件: ${availablePlugins.join(', ')}`);
58
+ process.exit(1);
59
+ }
60
+ const packageJsonPath = path.join(pluginDir, 'package.json');
61
+ if (!fs.existsSync(packageJsonPath)) {
62
+ logger.error(`未找到 package.json: ${packageJsonPath}`);
63
+ process.exit(1);
64
+ }
65
+ // 读取 package.json
66
+ const packageJson = await fs.readJson(packageJsonPath);
67
+ const packageName = packageJson.name;
68
+ const version = packageJson.version;
69
+ logger.info(`准备发布插件: ${packageName}@${version}`);
70
+ logger.log('');
71
+ // 确认发布
72
+ if (!options.dryRun) {
73
+ const { confirm } = await inquirer.prompt([
74
+ {
75
+ type: 'confirm',
76
+ name: 'confirm',
77
+ message: `确认发布 ${packageName}@${version} 到 npm?`,
78
+ default: false
79
+ }
80
+ ]);
81
+ if (!confirm) {
82
+ logger.warn('已取消发布');
83
+ process.exit(0);
84
+ }
85
+ }
86
+ // 构建插件
87
+ if (!options.skipBuild) {
88
+ logger.info('正在构建插件...');
89
+ try {
90
+ execSync('pnpm build', {
91
+ cwd: pluginDir,
92
+ stdio: 'inherit'
93
+ });
94
+ logger.success('✓ 构建完成');
95
+ }
96
+ catch (error) {
97
+ logger.error('构建失败');
98
+ throw error;
99
+ }
100
+ }
101
+ // 构建 npm publish 命令
102
+ const publishArgs = ['publish'];
103
+ if (options.access) {
104
+ publishArgs.push('--access', options.access);
105
+ }
106
+ if (options.tag) {
107
+ publishArgs.push('--tag', options.tag);
108
+ }
109
+ if (options.registry) {
110
+ publishArgs.push('--registry', options.registry);
111
+ }
112
+ if (options.dryRun) {
113
+ publishArgs.push('--dry-run');
114
+ }
115
+ // 总是添加 --no-git-checks(因为 plugins 可能不是 git 根目录)
116
+ publishArgs.push('--no-git-checks');
117
+ // 发布插件
118
+ logger.info(`正在发布${options.dryRun ? '(试运行)' : ''}...`);
119
+ logger.log(`命令: pnpm ${publishArgs.join(' ')}`);
120
+ logger.log('');
121
+ try {
122
+ execSync(`pnpm ${publishArgs.join(' ')}`, {
123
+ cwd: pluginDir,
124
+ stdio: 'inherit'
125
+ });
126
+ if (options.dryRun) {
127
+ logger.success('✓ 试运行完成');
128
+ logger.log('');
129
+ logger.log('💡 提示: 移除 --dry-run 参数以实际发布');
130
+ }
131
+ else {
132
+ logger.success(`✓ ${packageName}@${version} 发布成功!`);
133
+ logger.log('');
134
+ logger.log('📦 安装命令:');
135
+ logger.log(` pnpm add ${packageName}`);
136
+ logger.log('');
137
+ logger.log('🔗 npm 链接:');
138
+ logger.log(` https://www.npmjs.com/package/${packageName}`);
139
+ }
140
+ }
141
+ catch (error) {
142
+ logger.error('发布失败');
143
+ throw error;
144
+ }
145
+ }
146
+ catch (error) {
147
+ logger.error(`发布失败: ${error.message}`);
148
+ process.exit(1);
149
+ }
150
+ });
151
+ //# sourceMappingURL=pub.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pub.js","sourceRoot":"","sources":["../../src/commands/pub.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import { Command } from 'commander';
2
+ export declare const searchCommand: Command;
3
+ export declare const infoCommand: Command;
4
+ //# sourceMappingURL=search.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../src/commands/search.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAUpC,eAAO,MAAM,aAAa,SAyItB,CAAC;AAEL,eAAO,MAAM,WAAW,SA4FpB,CAAC"}
@@ -0,0 +1,205 @@
1
+ import { Command } from 'commander';
2
+ import { logger } from '../utils/logger.js';
3
+ import { execSync } from 'node:child_process';
4
+ export const searchCommand = new Command('search')
5
+ .description('搜索 Zhin.js 插件')
6
+ .argument('[keyword]', '搜索关键词')
7
+ .option('-c, --category <category>', '按分类搜索 (utility|service|game|adapter|admin|ai)')
8
+ .option('-l, --limit <number>', '限制结果数量', '20')
9
+ .option('--official', '仅显示官方插件', false)
10
+ .action(async (keyword, options) => {
11
+ try {
12
+ logger.info('正在搜索插件...');
13
+ logger.log('');
14
+ // 构建搜索查询
15
+ let searchQuery = 'zhin';
16
+ if (options.official) {
17
+ searchQuery = '@zhin.js';
18
+ }
19
+ else if (keyword) {
20
+ searchQuery = `zhin.js ${keyword} `;
21
+ }
22
+ else {
23
+ searchQuery = 'zhin.js plugin';
24
+ }
25
+ // 使用 npm search
26
+ const cmd = `npm search ${searchQuery} --json`;
27
+ try {
28
+ const output = execSync(cmd, {
29
+ encoding: 'utf-8',
30
+ maxBuffer: 10 * 1024 * 1024, // 10MB
31
+ stdio: ['pipe', 'pipe', 'ignore'] // 忽略 stderr
32
+ });
33
+ const results = JSON.parse(output);
34
+ // 过滤结果
35
+ let filteredResults = results.filter((pkg) => {
36
+ // 必须包含 zhin 关键词
37
+ const keywords = pkg.keywords || [];
38
+ const hasZhin = keywords.includes('zhin') ||
39
+ keywords.includes('plugin') ||
40
+ pkg.name.startsWith('@zhin.js/') ||
41
+ pkg.name.startsWith('zhin.js-');
42
+ if (!hasZhin)
43
+ return false;
44
+ // 按分类过滤
45
+ if (options.category) {
46
+ const category = pkg.keywords?.find((k) => k.includes(options.category));
47
+ if (!category)
48
+ return false;
49
+ }
50
+ // 按关键词过滤
51
+ if (keyword) {
52
+ const searchIn = [
53
+ pkg.name,
54
+ pkg.description || '',
55
+ ...(pkg.keywords || [])
56
+ ].join(' ').toLowerCase();
57
+ return searchIn.includes(keyword.toLowerCase());
58
+ }
59
+ return true;
60
+ });
61
+ // 限制结果数量
62
+ const limit = parseInt(String(options.limit) || '20');
63
+ if (filteredResults.length > limit) {
64
+ filteredResults = filteredResults.slice(0, limit);
65
+ }
66
+ // 显示结果
67
+ if (filteredResults.length === 0) {
68
+ logger.warn('未找到匹配的插件');
69
+ logger.log('');
70
+ logger.log('💡 提示:');
71
+ logger.log(' - 尝试使用不同的关键词');
72
+ logger.log(' - 访问插件市场: https://zhin.pages.dev/plugins');
73
+ logger.log(' - 在 GitHub 搜索: https://github.com/topics/zhin.js');
74
+ return;
75
+ }
76
+ logger.success(`找到 ${filteredResults.length} 个插件:`);
77
+ logger.log('');
78
+ // 按下载量排序
79
+ filteredResults.sort((a, b) => {
80
+ const aDownloads = parseInt(a.downloads || '0');
81
+ const bDownloads = parseInt(b.downloads || '0');
82
+ return bDownloads - aDownloads;
83
+ });
84
+ // 显示插件列表
85
+ filteredResults.forEach((pkg, index) => {
86
+ const name = pkg.name;
87
+ const version = pkg.version;
88
+ const description = pkg.description || '无描述';
89
+ const author = pkg.publisher?.username || '未知';
90
+ const date = pkg.date ? new Date(pkg.date).toLocaleDateString('zh-CN') : '未知';
91
+ // 判断插件类型
92
+ let badge = '';
93
+ if (name.startsWith('@zhin.js/')) {
94
+ badge = '✨ [官方]';
95
+ }
96
+ else if (name.startsWith('zhin.js-')) {
97
+ badge = '📦 [社区]';
98
+ }
99
+ logger.log(`${index + 1}. ${badge} ${name}@${version}`);
100
+ logger.log(` ${description}`);
101
+ logger.log(` 作者: ${author} | 更新: ${date}`);
102
+ // 显示安装命令
103
+ logger.log(` 安装: zhin install ${name}`);
104
+ logger.log('');
105
+ });
106
+ logger.log('💡 提示:');
107
+ logger.log(' - 使用 zhin info <package> 查看插件详情');
108
+ logger.log(' - 使用 zhin install <package> 安装插件');
109
+ logger.log(' - 访问 https://zhin.pages.dev/plugins 查看完整列表');
110
+ }
111
+ catch (error) {
112
+ logger.error('搜索失败,请检查网络连接');
113
+ logger.log('');
114
+ logger.log('💡 替代方案:');
115
+ logger.log(' - 访问 npm: https://www.npmjs.com/search?q=zhin.js');
116
+ logger.log(' - 访问 GitHub: https://github.com/topics/zhin.js');
117
+ throw error;
118
+ }
119
+ }
120
+ catch (error) {
121
+ logger.error(`搜索插件失败: ${error.message}`);
122
+ process.exit(1);
123
+ }
124
+ });
125
+ export const infoCommand = new Command('info')
126
+ .description('查看插件详细信息')
127
+ .argument('<package>', '插件包名')
128
+ .action(async (packageName) => {
129
+ try {
130
+ logger.info(`正在获取 ${packageName} 的信息...`);
131
+ logger.log('');
132
+ const cmd = `npm view ${packageName} --json`;
133
+ try {
134
+ const output = execSync(cmd, {
135
+ encoding: 'utf-8',
136
+ stdio: ['pipe', 'pipe', 'ignore']
137
+ });
138
+ const info = JSON.parse(output);
139
+ // 显示插件信息
140
+ logger.success('插件信息:');
141
+ logger.log('');
142
+ logger.log(`📦 名称: ${info.name}`);
143
+ logger.log(`📝 版本: ${info.version}`);
144
+ logger.log(`📄 描述: ${info.description || '无'}`);
145
+ logger.log(`👤 作者: ${info.author?.name || info.maintainers?.[0]?.name || '未知'}`);
146
+ logger.log(`📅 发布时间: ${new Date(info.time?.modified || info.time?.created).toLocaleDateString('zh-CN')}`);
147
+ if (info.keywords?.length > 0) {
148
+ logger.log(`🏷️ 标签: ${info.keywords.join(', ')}`);
149
+ }
150
+ if (info.homepage) {
151
+ logger.log(`🏠 主页: ${info.homepage}`);
152
+ }
153
+ if (info.repository?.url) {
154
+ logger.log(`📂 仓库: ${info.repository.url.replace(/^git\+/, '').replace(/\.git$/, '')}`);
155
+ }
156
+ if (info.bugs?.url) {
157
+ logger.log(`🐛 问题: ${info.bugs.url}`);
158
+ }
159
+ if (info.license) {
160
+ logger.log(`⚖️ 许可: ${info.license}`);
161
+ }
162
+ // 显示依赖
163
+ if (info.peerDependencies) {
164
+ logger.log('');
165
+ logger.log('🔗 对等依赖:');
166
+ Object.entries(info.peerDependencies).forEach(([dep, ver]) => {
167
+ logger.log(` ${dep}: ${ver}`);
168
+ });
169
+ }
170
+ // 显示安装命令
171
+ logger.log('');
172
+ logger.log('📥 安装命令:');
173
+ logger.log(` zhin install ${info.name}`);
174
+ logger.log(` # 或`);
175
+ logger.log(` pnpm add ${info.name}`);
176
+ // Zhin 特定信息
177
+ if (info.zhin) {
178
+ logger.log('');
179
+ logger.log('🎯 Zhin 信息:');
180
+ if (info.zhin.displayName) {
181
+ logger.log(` 显示名称: ${info.zhin.displayName}`);
182
+ }
183
+ if (info.zhin.category) {
184
+ logger.log(` 分类: ${info.zhin.category}`);
185
+ }
186
+ if (info.zhin.features?.length > 0) {
187
+ logger.log(` 功能: ${info.zhin.features.join(', ')}`);
188
+ }
189
+ }
190
+ }
191
+ catch (error) {
192
+ logger.error(`未找到插件: ${packageName}`);
193
+ logger.log('');
194
+ logger.log('💡 提示:');
195
+ logger.log(' - 检查插件名称是否正确');
196
+ logger.log(' - 使用 zhin search 搜索插件');
197
+ throw error;
198
+ }
199
+ }
200
+ catch (error) {
201
+ logger.error(`获取插件信息失败: ${error.message}`);
202
+ process.exit(1);
203
+ }
204
+ });
205
+ //# sourceMappingURL=search.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search.js","sourceRoot":"","sources":["../../src/commands/search.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zhin.js/cli",
3
- "version": "1.0.7",
3
+ "version": "1.0.8",
4
4
  "description": "Zhin机器人框架CLI工具",
5
5
  "type": "module",
6
6
  "main": "./lib/index.js",
package/src/cli.ts CHANGED
@@ -6,6 +6,9 @@ import { stopCommand } from './commands/stop.js';
6
6
  import { devCommand } from './commands/dev.js';
7
7
  import { buildCommand } from './commands/build.js';
8
8
  import { newCommand } from './commands/new.js';
9
+ import { pubCommand } from './commands/pub.js';
10
+ import { installCommand, addCommand } from './commands/install.js';
11
+ import { searchCommand, infoCommand } from './commands/search.js';
9
12
 
10
13
  const program = new Command();
11
14
 
@@ -21,5 +24,10 @@ program.addCommand(stopCommand);
21
24
  program.addCommand(devCommand);
22
25
  program.addCommand(buildCommand);
23
26
  program.addCommand(newCommand);
27
+ program.addCommand(pubCommand);
28
+ program.addCommand(installCommand);
29
+ program.addCommand(addCommand);
30
+ program.addCommand(searchCommand);
31
+ program.addCommand(infoCommand);
24
32
 
25
33
  program.parse();
@@ -0,0 +1,242 @@
1
+ import { Command } from 'commander';
2
+ import { logger } from '../utils/logger.js';
3
+ import fs from 'fs-extra';
4
+ import path from 'path';
5
+ import inquirer from 'inquirer';
6
+ import { execSync } from 'node:child_process';
7
+
8
+ interface InstallOptions {
9
+ save?: boolean;
10
+ saveDev?: boolean;
11
+ global?: boolean;
12
+ }
13
+
14
+ export const installCommand = new Command('install')
15
+ .description('安装插件(npm 包或 git 仓库)')
16
+ .argument('[plugin]', '插件名称或 git 地址')
17
+ .option('-S, --save', '安装到 dependencies(默认)', true)
18
+ .option('-D, --save-dev', '安装到 devDependencies', false)
19
+ .option('-g, --global', '全局安装', false)
20
+ .action(async (plugin: string, options: InstallOptions) => {
21
+ try {
22
+ let pluginToInstall = plugin;
23
+
24
+ // 如果没有指定插件,交互式输入
25
+ if (!pluginToInstall) {
26
+ const { input } = await inquirer.prompt([
27
+ {
28
+ type: 'input',
29
+ name: 'input',
30
+ message: '请输入插件名称或 git 地址:',
31
+ validate: (input: string) => {
32
+ if (!input.trim()) {
33
+ return '插件名称或地址不能为空';
34
+ }
35
+ return true;
36
+ }
37
+ }
38
+ ]);
39
+ pluginToInstall = input;
40
+ }
41
+
42
+ // 判断插件类型
43
+ const pluginType = detectPluginType(pluginToInstall);
44
+
45
+ logger.info(`检测到插件类型: ${pluginType}`);
46
+ logger.info(`正在安装: ${pluginToInstall}`);
47
+ logger.log('');
48
+
49
+ // 构建安装命令
50
+ const installCmd = buildInstallCommand(pluginToInstall, pluginType, options);
51
+
52
+ logger.log(`执行命令: ${installCmd}`);
53
+ logger.log('');
54
+
55
+ // 执行安装
56
+ try {
57
+ execSync(installCmd, {
58
+ cwd: process.cwd(),
59
+ stdio: 'inherit'
60
+ });
61
+
62
+ logger.success('✓ 插件安装成功!');
63
+ logger.log('');
64
+
65
+ // 如果是 git 插件,提供额外说明
66
+ if (pluginType === 'git') {
67
+ logger.log('📝 Git 插件已安装到 node_modules/');
68
+ logger.log('');
69
+ }
70
+
71
+ // 提示如何启用插件
72
+ const pluginName = extractPluginName(pluginToInstall, pluginType);
73
+ if (pluginName) {
74
+ logger.log('🔌 启用插件:');
75
+ logger.log(`在 zhin.config.ts 中添加:`);
76
+ logger.log('');
77
+ logger.log(' export default defineConfig({');
78
+ logger.log(' plugins: [');
79
+ logger.log(` '${pluginName}'`);
80
+ logger.log(' ]');
81
+ logger.log(' });');
82
+ }
83
+
84
+ } catch (error) {
85
+ logger.error('安装失败');
86
+ throw error;
87
+ }
88
+
89
+ } catch (error: any) {
90
+ logger.error(`安装插件失败: ${error.message}`);
91
+ process.exit(1);
92
+ }
93
+ });
94
+
95
+ // 别名命令
96
+ export const addCommand = new Command('add')
97
+ .description('安装插件(install 的别名)')
98
+ .argument('[plugin]', '插件名称或 git 地址')
99
+ .option('-S, --save', '安装到 dependencies(默认)', true)
100
+ .option('-D, --save-dev', '安装到 devDependencies', false)
101
+ .option('-g, --global', '全局安装', false)
102
+ .action(async (plugin: string, options: InstallOptions) => {
103
+ await installCommand.parseAsync(['node', 'zhin', 'install', plugin || '', ...buildOptionsArray(options)], { from: 'user' });
104
+ });
105
+
106
+ /**
107
+ * 检测插件类型
108
+ */
109
+ function detectPluginType(plugin: string): 'npm' | 'git' | 'github' | 'gitlab' | 'bitbucket' {
110
+ // Git 协议
111
+ if (plugin.startsWith('git://') || plugin.startsWith('git+')) {
112
+ return 'git';
113
+ }
114
+
115
+ // HTTPS/SSH git 地址
116
+ if (plugin.includes('github.com') || plugin.includes('gitlab.com') || plugin.includes('bitbucket.org')) {
117
+ if (plugin.includes('github.com')) return 'github';
118
+ if (plugin.includes('gitlab.com')) return 'gitlab';
119
+ if (plugin.includes('bitbucket.org')) return 'bitbucket';
120
+ return 'git';
121
+ }
122
+
123
+ // GitHub 简写 (user/repo)
124
+ if (/^[\w-]+\/[\w-]+$/.test(plugin)) {
125
+ return 'github';
126
+ }
127
+
128
+ // 默认为 npm 包
129
+ return 'npm';
130
+ }
131
+
132
+ /**
133
+ * 构建安装命令
134
+ */
135
+ function buildInstallCommand(plugin: string, type: string, options: InstallOptions): string {
136
+ const parts = ['pnpm', 'add'];
137
+
138
+ // 添加保存选项
139
+ if (options.saveDev) {
140
+ parts.push('-D');
141
+ }
142
+
143
+ if (options.global) {
144
+ parts.push('-g');
145
+ }
146
+
147
+ // 处理不同类型的插件
148
+ let packageSpec = plugin;
149
+
150
+ switch (type) {
151
+ case 'github':
152
+ // 如果是简写形式,转换为完整 GitHub URL
153
+ if (/^[\w-]+\/[\w-]+$/.test(plugin)) {
154
+ packageSpec = `github:${plugin}`;
155
+ } else if (!plugin.startsWith('git+') && !plugin.startsWith('https://')) {
156
+ packageSpec = `git+${plugin}`;
157
+ }
158
+ break;
159
+
160
+ case 'gitlab':
161
+ if (!plugin.startsWith('git+') && !plugin.startsWith('https://')) {
162
+ packageSpec = `git+${plugin}`;
163
+ }
164
+ break;
165
+
166
+ case 'bitbucket':
167
+ if (!plugin.startsWith('git+') && !plugin.startsWith('https://')) {
168
+ packageSpec = `git+${plugin}`;
169
+ }
170
+ break;
171
+
172
+ case 'git':
173
+ // Git URL 直接使用
174
+ break;
175
+
176
+ case 'npm':
177
+ default:
178
+ // npm 包名直接使用
179
+ break;
180
+ }
181
+
182
+ parts.push(packageSpec);
183
+
184
+ return parts.join(' ');
185
+ }
186
+
187
+ /**
188
+ * 提取插件名称
189
+ */
190
+ function extractPluginName(plugin: string, type: string): string | null {
191
+ switch (type) {
192
+ case 'npm':
193
+ // npm 包名可能包含 scope 和版本号
194
+ // @scope/package@version -> @scope/package 或 package
195
+ const match = plugin.match(/^(@?[\w-]+\/)?([^@]+)/);
196
+ if (match) {
197
+ const fullName = match[0].replace(/@[\d.]+.*$/, ''); // 移除版本号
198
+ // 如果是 @zhin.js/ 开头的包,提取最后的名称
199
+ if (fullName.startsWith('@zhin.js/')) {
200
+ return fullName.replace('@zhin.js/', '');
201
+ }
202
+ return fullName;
203
+ }
204
+ return plugin;
205
+
206
+ case 'github':
207
+ case 'gitlab':
208
+ case 'bitbucket':
209
+ // 从 git URL 中提取仓库名
210
+ const repoMatch = plugin.match(/\/([^/]+?)(\.git)?$/);
211
+ if (repoMatch) {
212
+ return repoMatch[1];
213
+ }
214
+ // 简写形式 user/repo
215
+ if (/^[\w-]+\/([\w-]+)$/.test(plugin)) {
216
+ return plugin.split('/')[1];
217
+ }
218
+ return null;
219
+
220
+ case 'git':
221
+ // 从 git URL 中提取仓库名
222
+ const gitMatch = plugin.match(/\/([^/]+?)(\.git)?$/);
223
+ if (gitMatch) {
224
+ return gitMatch[1];
225
+ }
226
+ return null;
227
+
228
+ default:
229
+ return null;
230
+ }
231
+ }
232
+
233
+ /**
234
+ * 构建选项数组
235
+ */
236
+ function buildOptionsArray(options: InstallOptions): string[] {
237
+ const arr: string[] = [];
238
+ if (options.saveDev) arr.push('-D');
239
+ if (options.global) arr.push('-g');
240
+ return arr;
241
+ }
242
+