@holic512/slothtool 1.0.1
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/README.md +81 -0
- package/bin/slothtool.js +50 -0
- package/lib/commands/index.js +11 -0
- package/lib/commands/install.js +15 -0
- package/lib/commands/list.js +22 -0
- package/lib/commands/run.js +41 -0
- package/lib/commands/uninstall.js +15 -0
- package/lib/plugin-manager.js +122 -0
- package/lib/registry.js +104 -0
- package/lib/utils.js +72 -0
- package/package.json +24 -0
package/README.md
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# SlothTool
|
|
2
|
+
|
|
3
|
+
🐌 A plugin manager and dispatcher for CLI tools.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install -g slothtool
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
# Install a plugin
|
|
15
|
+
slothtool install @slothtool/plugin-loc
|
|
16
|
+
|
|
17
|
+
# List installed plugins
|
|
18
|
+
slothtool list
|
|
19
|
+
|
|
20
|
+
# Run a plugin
|
|
21
|
+
slothtool loc ./src
|
|
22
|
+
|
|
23
|
+
# Uninstall a plugin
|
|
24
|
+
slothtool uninstall loc
|
|
25
|
+
|
|
26
|
+
# Get help
|
|
27
|
+
slothtool --help
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Commands
|
|
31
|
+
|
|
32
|
+
- `slothtool install <plugin>` - Install a plugin from npm
|
|
33
|
+
- `slothtool uninstall <plugin>` - Uninstall a plugin
|
|
34
|
+
- `slothtool list` - List all installed plugins
|
|
35
|
+
- `slothtool run <plugin> [args]` - Run a plugin with arguments
|
|
36
|
+
- `slothtool <plugin> [args]` - Shorthand for running a plugin
|
|
37
|
+
|
|
38
|
+
## Features
|
|
39
|
+
|
|
40
|
+
- **Zero Global Pollution**: Plugins are installed in `~/.slothtool/plugins/`
|
|
41
|
+
- **Plugin Isolation**: Each plugin has its own dependencies
|
|
42
|
+
- **Simple CLI**: Easy-to-use commands
|
|
43
|
+
- **Shorthand Syntax**: Run plugins directly with `slothtool <plugin>`
|
|
44
|
+
|
|
45
|
+
## How It Works
|
|
46
|
+
|
|
47
|
+
SlothTool manages CLI tools as plugins:
|
|
48
|
+
|
|
49
|
+
1. Plugins are npm packages with a `bin` field
|
|
50
|
+
2. When you install a plugin, it's downloaded to `~/.slothtool/plugins/`
|
|
51
|
+
3. SlothTool maintains a registry at `~/.slothtool/registry.json`
|
|
52
|
+
4. When you run a plugin, SlothTool spawns the plugin's executable
|
|
53
|
+
|
|
54
|
+
## Official Plugins
|
|
55
|
+
|
|
56
|
+
- [@holic512/plugin-loc](../plugin-loc) - Count lines of code
|
|
57
|
+
|
|
58
|
+
## Creating Plugins
|
|
59
|
+
|
|
60
|
+
Any npm package with a `bin` field can be a SlothTool plugin:
|
|
61
|
+
|
|
62
|
+
```json
|
|
63
|
+
{
|
|
64
|
+
"name": "@yourscope/plugin-mytool",
|
|
65
|
+
"version": "1.0.0",
|
|
66
|
+
"bin": {
|
|
67
|
+
"mytool": "bin/my-tool.js"
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Publish to npm and users can install it:
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
slothtool install @yourscope/plugin-mytool
|
|
76
|
+
slothtool mytool
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## License
|
|
80
|
+
|
|
81
|
+
ISC
|
package/bin/slothtool.js
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const commands = require('../lib/commands');
|
|
4
|
+
|
|
5
|
+
const args = process.argv.slice(2);
|
|
6
|
+
const command = args[0];
|
|
7
|
+
|
|
8
|
+
// 如果没有参数,显示帮助信息
|
|
9
|
+
if (!command) {
|
|
10
|
+
console.log('🐌 SlothTool - A plugin manager for CLI tools\n');
|
|
11
|
+
console.log('Usage:');
|
|
12
|
+
console.log(' slothtool install <plugin> Install a plugin');
|
|
13
|
+
console.log(' slothtool uninstall <plugin> Uninstall a plugin');
|
|
14
|
+
console.log(' slothtool list List installed plugins');
|
|
15
|
+
console.log(' slothtool run <plugin> [args] Run a plugin');
|
|
16
|
+
console.log(' slothtool <plugin> [args] Run a plugin (shorthand)\n');
|
|
17
|
+
console.log('Examples:');
|
|
18
|
+
console.log(' slothtool install @holic512/plugin-loc');
|
|
19
|
+
console.log(' slothtool loc ./src');
|
|
20
|
+
console.log(' slothtool list');
|
|
21
|
+
process.exit(0);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// 内置命令
|
|
25
|
+
if (command === 'install') {
|
|
26
|
+
commands.install(args.slice(1));
|
|
27
|
+
} else if (command === 'uninstall') {
|
|
28
|
+
commands.uninstall(args.slice(1));
|
|
29
|
+
} else if (command === 'list') {
|
|
30
|
+
commands.list();
|
|
31
|
+
} else if (command === 'run') {
|
|
32
|
+
commands.run(args.slice(1));
|
|
33
|
+
} else if (command === '--help' || command === '-h') {
|
|
34
|
+
console.log('🐌 SlothTool - A plugin manager for CLI tools\n');
|
|
35
|
+
console.log('Usage:');
|
|
36
|
+
console.log(' slothtool install <plugin> Install a plugin');
|
|
37
|
+
console.log(' slothtool uninstall <plugin> Uninstall a plugin');
|
|
38
|
+
console.log(' slothtool list List installed plugins');
|
|
39
|
+
console.log(' slothtool run <plugin> [args] Run a plugin');
|
|
40
|
+
console.log(' slothtool <plugin> [args] Run a plugin (shorthand)\n');
|
|
41
|
+
console.log('Examples:');
|
|
42
|
+
console.log(' slothtool install @holic512/plugin-loc');
|
|
43
|
+
console.log(' slothtool loc ./src');
|
|
44
|
+
console.log(' slothtool list');
|
|
45
|
+
process.exit(0);
|
|
46
|
+
} else {
|
|
47
|
+
// 简写形式:slothtool <plugin> [...args]
|
|
48
|
+
// 直接将所有参数传递给 run 命令
|
|
49
|
+
commands.run(args);
|
|
50
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
const { installPlugin } = require('../plugin-manager');
|
|
2
|
+
|
|
3
|
+
function install(args) {
|
|
4
|
+
if (args.length === 0) {
|
|
5
|
+
console.error('Error: Please specify a plugin to install.');
|
|
6
|
+
console.log('Usage: slothtool install <plugin-name>');
|
|
7
|
+
console.log('Example: slothtool install @slothtool/plugin-loc');
|
|
8
|
+
process.exit(1);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const packageName = args[0];
|
|
12
|
+
installPlugin(packageName);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
module.exports = install;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
const registry = require('../registry');
|
|
2
|
+
|
|
3
|
+
function list() {
|
|
4
|
+
const plugins = registry.getAllPlugins();
|
|
5
|
+
|
|
6
|
+
if (Object.keys(plugins).length === 0) {
|
|
7
|
+
console.log('No plugins installed.');
|
|
8
|
+
console.log('\nInstall a plugin with: slothtool install <plugin-name>');
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
console.log('Installed plugins:\n');
|
|
13
|
+
for (const [alias, info] of Object.entries(plugins)) {
|
|
14
|
+
console.log(` ${alias}`);
|
|
15
|
+
console.log(` Package: ${info.name}`);
|
|
16
|
+
console.log(` Version: ${info.version}`);
|
|
17
|
+
console.log(` Installed: ${new Date(info.installedAt).toLocaleString()}`);
|
|
18
|
+
console.log('');
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
module.exports = list;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
const { spawn } = require('child_process');
|
|
2
|
+
const registry = require('../registry');
|
|
3
|
+
|
|
4
|
+
function run(args) {
|
|
5
|
+
if (args.length === 0) {
|
|
6
|
+
console.error('Error: Please specify a plugin to run.');
|
|
7
|
+
console.log('Usage: slothtool run <plugin-alias> [args...]');
|
|
8
|
+
console.log(' or: slothtool <plugin-alias> [args...]');
|
|
9
|
+
console.log('\nExample: slothtool run loc ./src');
|
|
10
|
+
console.log(' or: slothtool loc ./src');
|
|
11
|
+
process.exit(1);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const pluginAlias = args[0];
|
|
15
|
+
const pluginArgs = args.slice(1);
|
|
16
|
+
|
|
17
|
+
const plugin = registry.getPlugin(pluginAlias);
|
|
18
|
+
|
|
19
|
+
if (!plugin) {
|
|
20
|
+
console.error(`Error: Plugin "${pluginAlias}" not found.`);
|
|
21
|
+
console.log(`\nRun "slothtool list" to see installed plugins.`);
|
|
22
|
+
console.log(`Or install it with: slothtool install <plugin-name>`);
|
|
23
|
+
process.exit(1);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// 调用插件
|
|
27
|
+
const child = spawn('node', [plugin.binPath, ...pluginArgs], {
|
|
28
|
+
stdio: 'inherit'
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
child.on('error', (error) => {
|
|
32
|
+
console.error(`Failed to run plugin "${pluginAlias}":`, error.message);
|
|
33
|
+
process.exit(1);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
child.on('exit', (code) => {
|
|
37
|
+
process.exit(code || 0);
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
module.exports = run;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
const { uninstallPlugin } = require('../plugin-manager');
|
|
2
|
+
|
|
3
|
+
function uninstall(args) {
|
|
4
|
+
if (args.length === 0) {
|
|
5
|
+
console.error('Error: Please specify a plugin to uninstall.');
|
|
6
|
+
console.log('Usage: slothtool uninstall <plugin-alias>');
|
|
7
|
+
console.log('Example: slothtool uninstall loc');
|
|
8
|
+
process.exit(1);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const alias = args[0];
|
|
12
|
+
uninstallPlugin(alias);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
module.exports = uninstall;
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
const { execSync } = require('child_process');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const registry = require('./registry');
|
|
5
|
+
const { extractPluginAlias, getPluginDir, ensureDir, getPluginsDir } = require('./utils');
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* 安装插件
|
|
9
|
+
* @param {string} packageName - npm 包名 (例如: @slothtool/plugin-loc 或 plugin-loc)
|
|
10
|
+
*/
|
|
11
|
+
function installPlugin(packageName) {
|
|
12
|
+
console.log(`Installing plugin: ${packageName}...`);
|
|
13
|
+
|
|
14
|
+
// 提取插件别名
|
|
15
|
+
const alias = extractPluginAlias(packageName);
|
|
16
|
+
|
|
17
|
+
// 检查是否已安装
|
|
18
|
+
if (registry.hasPlugin(alias)) {
|
|
19
|
+
console.log(`Plugin "${alias}" is already installed.`);
|
|
20
|
+
console.log(`Run "slothtool uninstall ${alias}" first if you want to reinstall.`);
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// 确保插件目录存在
|
|
25
|
+
ensureDir(getPluginsDir());
|
|
26
|
+
|
|
27
|
+
const pluginDir = getPluginDir(alias);
|
|
28
|
+
ensureDir(pluginDir);
|
|
29
|
+
|
|
30
|
+
try {
|
|
31
|
+
// 使用 npm install 安装插件到指定目录
|
|
32
|
+
console.log(`Installing to: ${pluginDir}`);
|
|
33
|
+
execSync(`npm install ${packageName} --prefix "${pluginDir}"`, {
|
|
34
|
+
stdio: 'inherit',
|
|
35
|
+
encoding: 'utf8'
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
// 读取插件的 package.json
|
|
39
|
+
const pkgPath = path.join(pluginDir, 'node_modules', packageName, 'package.json');
|
|
40
|
+
|
|
41
|
+
if (!fs.existsSync(pkgPath)) {
|
|
42
|
+
throw new Error(`Package.json not found at: ${pkgPath}`);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
|
|
46
|
+
|
|
47
|
+
// 获取 bin 路径
|
|
48
|
+
let binPath;
|
|
49
|
+
if (typeof pkg.bin === 'string') {
|
|
50
|
+
binPath = path.join(pluginDir, 'node_modules', packageName, pkg.bin);
|
|
51
|
+
} else if (typeof pkg.bin === 'object') {
|
|
52
|
+
// 如果 bin 是对象,取第一个值
|
|
53
|
+
const binKey = Object.keys(pkg.bin)[0];
|
|
54
|
+
binPath = path.join(pluginDir, 'node_modules', packageName, pkg.bin[binKey]);
|
|
55
|
+
} else {
|
|
56
|
+
throw new Error(`No bin field found in package.json for ${packageName}`);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// 验证 bin 文件存在
|
|
60
|
+
if (!fs.existsSync(binPath)) {
|
|
61
|
+
throw new Error(`Bin file not found at: ${binPath}`);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// 添加到注册表
|
|
65
|
+
registry.addPlugin(alias, {
|
|
66
|
+
name: packageName,
|
|
67
|
+
version: pkg.version,
|
|
68
|
+
binPath: binPath,
|
|
69
|
+
installedAt: new Date().toISOString()
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
console.log(`\n✓ Plugin "${alias}" installed successfully!`);
|
|
73
|
+
console.log(` Run: slothtool ${alias} --help`);
|
|
74
|
+
|
|
75
|
+
} catch (error) {
|
|
76
|
+
console.error(`\n✗ Failed to install plugin "${packageName}":`, error.message);
|
|
77
|
+
|
|
78
|
+
// 清理失败的安装
|
|
79
|
+
if (fs.existsSync(pluginDir)) {
|
|
80
|
+
fs.rmSync(pluginDir, { recursive: true, force: true });
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
process.exit(1);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* 卸载插件
|
|
89
|
+
* @param {string} alias - 插件别名
|
|
90
|
+
*/
|
|
91
|
+
function uninstallPlugin(alias) {
|
|
92
|
+
const plugin = registry.getPlugin(alias);
|
|
93
|
+
|
|
94
|
+
if (!plugin) {
|
|
95
|
+
console.error(`Plugin "${alias}" is not installed.`);
|
|
96
|
+
process.exit(1);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
console.log(`Uninstalling plugin: ${alias}...`);
|
|
100
|
+
|
|
101
|
+
try {
|
|
102
|
+
// 删除插件目录
|
|
103
|
+
const pluginDir = getPluginDir(alias);
|
|
104
|
+
if (fs.existsSync(pluginDir)) {
|
|
105
|
+
fs.rmSync(pluginDir, { recursive: true, force: true });
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// 从注册表移除
|
|
109
|
+
registry.removePlugin(alias);
|
|
110
|
+
|
|
111
|
+
console.log(`✓ Plugin "${alias}" uninstalled successfully!`);
|
|
112
|
+
|
|
113
|
+
} catch (error) {
|
|
114
|
+
console.error(`✗ Failed to uninstall plugin "${alias}":`, error.message);
|
|
115
|
+
process.exit(1);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
module.exports = {
|
|
120
|
+
installPlugin,
|
|
121
|
+
uninstallPlugin
|
|
122
|
+
};
|
package/lib/registry.js
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const { getRegistryPath, ensureDir, getSlothToolHome } = require('./utils');
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* 读取注册表
|
|
6
|
+
* @returns {Object} 注册表对象
|
|
7
|
+
*/
|
|
8
|
+
function readRegistry() {
|
|
9
|
+
const registryPath = getRegistryPath();
|
|
10
|
+
|
|
11
|
+
// 确保 .slothtool 目录存在
|
|
12
|
+
ensureDir(getSlothToolHome());
|
|
13
|
+
|
|
14
|
+
// 如果注册表文件不存在,返回空对象
|
|
15
|
+
if (!fs.existsSync(registryPath)) {
|
|
16
|
+
return { plugins: {} };
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
try {
|
|
20
|
+
const content = fs.readFileSync(registryPath, 'utf8');
|
|
21
|
+
return JSON.parse(content);
|
|
22
|
+
} catch (error) {
|
|
23
|
+
console.error('Failed to read registry:', error.message);
|
|
24
|
+
return { plugins: {} };
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* 写入注册表
|
|
30
|
+
* @param {Object} registry - 注册表对象
|
|
31
|
+
*/
|
|
32
|
+
function writeRegistry(registry) {
|
|
33
|
+
const registryPath = getRegistryPath();
|
|
34
|
+
|
|
35
|
+
// 确保 .slothtool 目录存在
|
|
36
|
+
ensureDir(getSlothToolHome());
|
|
37
|
+
|
|
38
|
+
try {
|
|
39
|
+
fs.writeFileSync(registryPath, JSON.stringify(registry, null, 2), 'utf8');
|
|
40
|
+
} catch (error) {
|
|
41
|
+
console.error('Failed to write registry:', error.message);
|
|
42
|
+
throw error;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* 添加插件到注册表
|
|
48
|
+
* @param {string} alias - 插件别名
|
|
49
|
+
* @param {Object} pluginInfo - 插件信息
|
|
50
|
+
*/
|
|
51
|
+
function addPlugin(alias, pluginInfo) {
|
|
52
|
+
const registry = readRegistry();
|
|
53
|
+
registry.plugins[alias] = pluginInfo;
|
|
54
|
+
writeRegistry(registry);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* 从注册表移除插件
|
|
59
|
+
* @param {string} alias - 插件别名
|
|
60
|
+
*/
|
|
61
|
+
function removePlugin(alias) {
|
|
62
|
+
const registry = readRegistry();
|
|
63
|
+
delete registry.plugins[alias];
|
|
64
|
+
writeRegistry(registry);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* 获取插件信息
|
|
69
|
+
* @param {string} alias - 插件别名
|
|
70
|
+
* @returns {Object|null} 插件信息,如果不存在返回 null
|
|
71
|
+
*/
|
|
72
|
+
function getPlugin(alias) {
|
|
73
|
+
const registry = readRegistry();
|
|
74
|
+
return registry.plugins[alias] || null;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* 获取所有插件
|
|
79
|
+
* @returns {Object} 所有插件的映射
|
|
80
|
+
*/
|
|
81
|
+
function getAllPlugins() {
|
|
82
|
+
const registry = readRegistry();
|
|
83
|
+
return registry.plugins;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* 检查插件是否已安装
|
|
88
|
+
* @param {string} alias - 插件别名
|
|
89
|
+
* @returns {boolean} 是否已安装
|
|
90
|
+
*/
|
|
91
|
+
function hasPlugin(alias) {
|
|
92
|
+
const registry = readRegistry();
|
|
93
|
+
return alias in registry.plugins;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
module.exports = {
|
|
97
|
+
readRegistry,
|
|
98
|
+
writeRegistry,
|
|
99
|
+
addPlugin,
|
|
100
|
+
removePlugin,
|
|
101
|
+
getPlugin,
|
|
102
|
+
getAllPlugins,
|
|
103
|
+
hasPlugin
|
|
104
|
+
};
|
package/lib/utils.js
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
const os = require('os');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* 获取 slothtool 的主目录
|
|
7
|
+
* @returns {string} ~/.slothtool
|
|
8
|
+
*/
|
|
9
|
+
function getSlothToolHome() {
|
|
10
|
+
return path.join(os.homedir(), '.slothtool');
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* 获取插件安装目录
|
|
15
|
+
* @returns {string} ~/.slothtool/plugins
|
|
16
|
+
*/
|
|
17
|
+
function getPluginsDir() {
|
|
18
|
+
return path.join(getSlothToolHome(), 'plugins');
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* 获取注册表文件路径
|
|
23
|
+
* @returns {string} ~/.slothtool/registry.json
|
|
24
|
+
*/
|
|
25
|
+
function getRegistryPath() {
|
|
26
|
+
return path.join(getSlothToolHome(), 'registry.json');
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* 确保目录存在,如果不存在则创建
|
|
31
|
+
* @param {string} dir - 目录路径
|
|
32
|
+
*/
|
|
33
|
+
function ensureDir(dir) {
|
|
34
|
+
if (!fs.existsSync(dir)) {
|
|
35
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* 从完整的包名中提取插件别名
|
|
41
|
+
* 例如: @slothtool/plugin-loc -> loc
|
|
42
|
+
* plugin-loc -> loc
|
|
43
|
+
* @param {string} packageName - npm 包名
|
|
44
|
+
* @returns {string} 插件别名
|
|
45
|
+
*/
|
|
46
|
+
function extractPluginAlias(packageName) {
|
|
47
|
+
// 移除 scope (如果有)
|
|
48
|
+
const withoutScope = packageName.replace(/^@[^/]+\//, '');
|
|
49
|
+
|
|
50
|
+
// 移除 plugin- 前缀 (如果有)
|
|
51
|
+
const alias = withoutScope.replace(/^plugin-/, '');
|
|
52
|
+
|
|
53
|
+
return alias;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* 获取指定插件的安装目录
|
|
58
|
+
* @param {string} pluginAlias - 插件别名
|
|
59
|
+
* @returns {string} 插件安装目录路径
|
|
60
|
+
*/
|
|
61
|
+
function getPluginDir(pluginAlias) {
|
|
62
|
+
return path.join(getPluginsDir(), pluginAlias);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
module.exports = {
|
|
66
|
+
getSlothToolHome,
|
|
67
|
+
getPluginsDir,
|
|
68
|
+
getRegistryPath,
|
|
69
|
+
ensureDir,
|
|
70
|
+
extractPluginAlias,
|
|
71
|
+
getPluginDir
|
|
72
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@holic512/slothtool",
|
|
3
|
+
"version": "1.0.1",
|
|
4
|
+
"description": "A plugin manager and dispatcher for CLI tools",
|
|
5
|
+
"main": "lib/index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"slothtool": "bin/slothtool.js"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
11
|
+
},
|
|
12
|
+
"keywords": [
|
|
13
|
+
"cli",
|
|
14
|
+
"plugin",
|
|
15
|
+
"tool",
|
|
16
|
+
"manager"
|
|
17
|
+
],
|
|
18
|
+
"author": "",
|
|
19
|
+
"license": "ISC",
|
|
20
|
+
"files": [
|
|
21
|
+
"bin",
|
|
22
|
+
"lib"
|
|
23
|
+
]
|
|
24
|
+
}
|