clash-kit 1.0.0 → 1.0.2

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 CHANGED
@@ -1,4 +1,6 @@
1
- # Clash CLI
1
+ # Clash Kit
2
+
3
+ <img width="800" alt="clash-kit" src="https://github.com/user-attachments/assets/dd7dfd29-f59a-418b-8623-6ab08ece9ddb" />
2
4
 
3
5
  一个基于 Node.js 的 Clash 命令行管理工具,旨在简化 Clash 的配置管理、订阅切换和节点测速等操作。
4
6
 
@@ -12,7 +14,7 @@
12
14
  - 🛠 **自动初始化**:自动处理二进制文件权限问题。
13
15
 
14
16
  - 💻 **系统代理**:一键开启/关闭 macOS 系统 HTTP 代理。
15
- - 🛡 **TUN 模式**:高级网络模式,接管系统所有流量(类 VPN 体验)。
17
+ - 🛡 **TUN 模式**:高级网络模式,接管系统所有流量(真 · 全局代理)。
16
18
 
17
19
  ## 使用
18
20
 
@@ -30,6 +32,8 @@ pnpm add -g clash-kit
30
32
 
31
33
  ```bash
32
34
  clash init
35
+ # 推荐用简化命令(文档后续均以简化命令为例)
36
+ ck init
33
37
  ```
34
38
 
35
39
  ### 3. 启动服务
@@ -38,58 +42,62 @@ clash init
38
42
 
39
43
  ```bash
40
44
  # 启动 Clash 代理服务
41
- clash start
45
+ ck start
42
46
 
43
47
  # 启动并自动开启系统代理
44
- clash start -s
48
+ ck start -s
45
49
  ```
46
50
 
47
51
  ### 4. 添加订阅
48
52
 
49
53
  ```bash
50
- # 交互式管理订阅(添加、切换、删除等)
51
- clash sub
54
+ # 交互式管理订阅(添加、切换、删除等)【推荐使用这种方式来管理订阅】
55
+ ck sub
52
56
 
53
57
  # 手动添加订阅
54
- clash sub -a "https://example.com/subscribe?token=xxx" -n "abcName"
58
+ ck sub -a "https://example.com/subscribe?token=xxx" -n "abcName"
55
59
  ```
56
60
 
57
61
  ### 4. 节点测速与切换
58
62
 
59
63
  ```bash
60
64
  # 测速
61
- clash test
65
+ ck test
62
66
 
63
67
  # 切换节点
64
- clash proxy
68
+ ck proxy
65
69
  ```
66
70
 
67
71
  ### 5. 更多功能
68
72
 
69
73
  ```bash
70
74
  # 查看状态
71
- clash status
75
+ ck status
72
76
 
73
77
  # 开启 TUN 模式 (需要 sudo 权限)
74
- sudo clash tun on
78
+ sudo ck tun on
75
79
  ```
76
80
 
77
81
  ## 命令详解
78
82
 
79
- | 命令 | 说明 | 示例 |
80
- | --------------------- | -------------------------- | ------------------------------------- |
81
- | `clash init` | 初始化内核及权限 | `clash init` |
82
- | `clash start` | 启动 Clash 服务 | `clash start -s` (启动并设置系统代理) |
83
- | `clash stop` | 停止服务并关闭代理 | `clash stop` |
84
- | `clash status` | 查看运行状态及当前节点延迟 | `clash status` |
85
- | `clash sub`(推荐) | 管理订阅(交互式) | `clash sub` |
86
- | `clash sub -a <url>` | 添加订阅 | `clash sub -a "http..." -n "pro"` |
87
- | `clash sub -u <name>` | 切换订阅 | `clash sub -u "pro"` |
88
- | `clash sub -l` | 列出所有订阅 | `clash sub -l` |
89
- | `clash proxy` | 切换节点(交互式) | `clash proxy` |
90
- | `clash test` | 节点并发测速 | `clash test` |
91
- | `clash sysproxy` | 设置系统代理 (on/off) | `clash sysproxy on` |
92
- | `clash tun` | 设置 TUN 模式 (on/off) | `sudo clash tun on` |
83
+ | 命令 (别名) | 说明 | 示例 |
84
+ | --------------------- | -------------------------- | ------------------------------- |
85
+ | `ck init` (`i`) | 初始化内核及权限 | `ck i` |
86
+ | `ck start` (`on`) | 启动 Clash 服务 | `ck on -s` (启动并设置系统代理) |
87
+ | `ck stop` (`off`) | 停止服务并关闭代理 | `ck off` |
88
+ | `ck status` (`st`) | 查看运行状态及当前节点延迟 | `ck st` |
89
+ | `ck sub` (`s`) | 管理订阅(交互式) | `ck s` |
90
+ | `ck sub -a <url>` | 添加订阅 | `ck s -a "http..." -n "pro"` |
91
+ | `ck sub -u <name>` | 切换订阅 | `ck s -u "pro"` |
92
+ | `ck sub -l` | 列出所有订阅 | `ck s -l` |
93
+ | `ck proxy` (`p`) | 切换节点(交互式) | `ck p` |
94
+ | `ck test` (`t`) | 节点并发测速 | `ck t` |
95
+ | `ck sysproxy` (`sys`) | 设置系统代理 (on/off) | `ck sys on` |
96
+ | `ck tun` | 设置 TUN 模式 (on/off) | `sudo ck tun on` |
97
+
98
+ ## 截图
99
+
100
+ <img width="2742" height="1994" alt="image" src="https://github.com/user-attachments/assets/1183f778-62b0-4ac7-ab55-b821b66161f0" />
93
101
 
94
102
  ## 目录结构
95
103
 
package/bin/index.js CHANGED
@@ -13,7 +13,7 @@ import { test } from '../lib/commands/test.js'
13
13
 
14
14
  const program = new Command()
15
15
 
16
- program.name('clash').description('Clash CLI 管理工具').version('1.0.0')
16
+ program.name('clash').alias('ck').description('Clash CLI 管理工具 (Alias: ck)').version('1.0.0')
17
17
 
18
18
  // 初始化 clash 内核
19
19
  program
@@ -29,13 +29,18 @@ program.command('start').description('启动 Clash 服务').option('-s, --syspro
29
29
  program.command('stop').description('停止 Clash 服务').action(stop)
30
30
 
31
31
  // 设置系统代理
32
- program.command('sysproxy').description('设置系统代理').argument('[action]', 'on 或 off').action(setSysProxy)
32
+ program
33
+ .command('sysproxy')
34
+ .alias('sys')
35
+ .description('设置系统代理')
36
+ .argument('[action]', 'on 或 off')
37
+ .action(setSysProxy)
33
38
 
34
39
  // 设置 TUN 模式(真正的全局代理,所有流量都会被代理)
35
40
  program.command('tun').description('设置 TUN 模式 (可能需要提权)').argument('[action]', 'on 或 off').action(setTun)
36
41
 
37
42
  // 查看 clash 状态
38
- program.command('status').description('查看 Clash 运行状态').action(status)
43
+ program.command('status').alias('st').description('查看 Clash 运行状态').action(status)
39
44
 
40
45
  // 管理订阅
41
46
  program
@@ -48,9 +53,9 @@ program
48
53
  .action(manageSub)
49
54
 
50
55
  // 切换节点
51
- program.command('proxy').description('切换节点').action(proxy)
56
+ program.command('proxy').alias('p').description('切换节点').action(proxy)
52
57
 
53
58
  // 节点测速
54
- program.command('test').description('节点测速').action(test)
59
+ program.command('test').alias('t').description('节点测速').action(test)
55
60
 
56
61
  program.parse(process.argv)
package/country.mmdb ADDED
Binary file
package/default.yaml ADDED
@@ -0,0 +1,46 @@
1
+ # HTTP 代理端口
2
+ port: 7890
3
+ # SOCKS5 代理端口
4
+ socks-port: 7891
5
+ # 允许局域网连接
6
+ allow-lan: true
7
+
8
+ # 规则模式:Rule(规则) / Global(全局)/ Direct(直连)
9
+ mode: Rule
10
+ # 日志级别:info / warning / error / debug / silent
11
+ log-level: info
12
+ # 外部控制接口(用于 Dashboard)
13
+ external-controller: 127.0.0.1:9090
14
+
15
+ # 代理节点定义 (示例)
16
+ proxies:
17
+ # - name: "Shadowsocks 示例"
18
+ # type: ss
19
+ # server: server
20
+ # port: 443
21
+ # cipher: chacha20-ietf-poly1305
22
+ # password: "password"
23
+
24
+ # - name: "Vmess 示例"
25
+ # type: vmess
26
+ # server: server
27
+ # port: 443
28
+ # uuid: uuid
29
+ # alterId: 64
30
+ # cipher: auto
31
+
32
+ # 代理组定义
33
+ proxy-groups:
34
+ - name: PROXY
35
+ type: select
36
+ proxies:
37
+ - DIRECT
38
+ # - "Shadowsocks 示例"
39
+
40
+ # 规则定义
41
+ rules:
42
+ - DOMAIN-SUFFIX,google.com,PROXY
43
+ - DOMAIN-KEYWORD,google,PROXY
44
+ - DOMAIN,google.com,PROXY
45
+ - GEOIP,CN,DIRECT
46
+ - MATCH,PROXY
package/lib/api.js CHANGED
@@ -104,3 +104,13 @@ export async function reloadConfig(configPath) {
104
104
  throw new Error(`重载配置失败: ${err.message}`)
105
105
  }
106
106
  }
107
+
108
+ export async function isClashRunning() {
109
+ try {
110
+ // 使用较短的超时时间快速检查
111
+ await axios.get(`${getApiBase()}/version`, { timeout: 200 })
112
+ return true
113
+ } catch (err) {
114
+ return false
115
+ }
116
+ }
@@ -2,12 +2,57 @@ import path from 'path'
2
2
  import fs from 'fs'
3
3
  import { fileURLToPath } from 'url'
4
4
  import { downloadClash } from '../kernel.js'
5
+ import axios from 'axios'
6
+ import ora from 'ora'
7
+ import chalk from 'chalk'
5
8
 
6
9
  const __filename = fileURLToPath(import.meta.url)
7
10
  const __dirname = path.dirname(__filename)
8
11
 
9
- const DEFAULT_CONFIG = `mixed-port: 7890
10
- `
12
+ const DEFAULT_CONFIG = `mixed-port: 7890\n`
13
+
14
+ const RESOURCES = [
15
+ {
16
+ filename: 'country.mmdb',
17
+ url: 'https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/country-lite.mmdb',
18
+ },
19
+ // {
20
+ // filename: 'geoip.metadb',
21
+ // url: 'https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geoip.metadb',
22
+ // },
23
+ // {
24
+ // filename: 'geosite.dat',
25
+ // url: 'https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geosite.dat',
26
+ // },
27
+ // {
28
+ // filename: 'geoip.dat',
29
+ // url: 'https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geoip.dat',
30
+ // },
31
+ // {
32
+ // filename: 'ASN.mmdb',
33
+ // url: 'https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/GeoLite2-ASN.mmdb',
34
+ // },
35
+ ]
36
+
37
+ async function downloadResource(resource, targetDir) {
38
+ const filePath = path.join(targetDir, resource.filename)
39
+ const spinner = ora(`正在下载 ${resource.filename}...`).start()
40
+
41
+ try {
42
+ const response = await axios({
43
+ url: resource.url,
44
+ method: 'GET',
45
+ responseType: 'arraybuffer',
46
+ timeout: 30 * 1000, // 30s timeout
47
+ })
48
+ fs.writeFileSync(filePath, response.data)
49
+ spinner.succeed(`${resource.filename} 下载完成`)
50
+ } catch (e) {
51
+ spinner.fail(`${resource.filename} 下载失败: ${e.message}`)
52
+ // 不要抛出错误,让其他资源继续下载
53
+ // throw e
54
+ }
55
+ }
11
56
 
12
57
  export async function init(options) {
13
58
  const rootDir = path.join(__dirname, '../..')
@@ -18,9 +63,33 @@ export async function init(options) {
18
63
  try {
19
64
  // 创建默认配置文件(如果不存在)
20
65
  if (!fs.existsSync(configPath)) {
21
- fs.writeFileSync(configPath, DEFAULT_CONFIG, 'utf8')
22
- console.log(`已创建默认配置文件: ${configPath}`)
66
+ const defaultConfigPath = path.join(rootDir, 'default.yaml')
67
+ if (fs.existsSync(defaultConfigPath)) {
68
+ fs.copyFileSync(defaultConfigPath, configPath)
69
+ console.log(`已从 default.yaml 创建配置文件: ${configPath}`)
70
+ } else {
71
+ console.warn(chalk.yellow('警告: 未找到 default.yaml,将创建最小配置文件'))
72
+ fs.writeFileSync(configPath, DEFAULT_CONFIG, 'utf8')
73
+ }
74
+ }
75
+
76
+ // 检查并下载资源文件
77
+ console.log(chalk.blue('\n正在检查资源文件...'))
78
+ for (const resource of RESOURCES) {
79
+ const filePath = path.join(rootDir, resource.filename)
80
+ if (options.force && fs.existsSync(filePath)) {
81
+ try {
82
+ fs.unlinkSync(filePath)
83
+ } catch (e) {}
84
+ }
85
+
86
+ if (!fs.existsSync(filePath)) {
87
+ await downloadResource(resource, rootDir)
88
+ } else {
89
+ console.log(chalk.gray(`资源 ${resource.filename} 已存在`))
90
+ }
23
91
  }
92
+ console.log(chalk.green('资源检查完成\n'))
24
93
 
25
94
  if (fs.existsSync(binPath) && !options.force) {
26
95
  console.log(`Clash 内核已存在: ${binPath}`)
@@ -23,10 +23,7 @@ async function handleAddSubscription(url, name) {
23
23
 
24
24
  export async function manageSub(options) {
25
25
  if (options.add) {
26
- if (!options.name) {
27
- console.error('错误: 添加订阅时必须指定名称 (-n)')
28
- return
29
- }
26
+ if (!options.name) return console.error('错误: 添加订阅时必须指定名称 (-n)')
30
27
  try {
31
28
  await handleAddSubscription(options.add, options.name)
32
29
  } catch (err) {
@@ -34,7 +31,7 @@ export async function manageSub(options) {
34
31
  }
35
32
  } else if (options.list) {
36
33
  const profiles = sub.listProfiles()
37
- console.log('可用订阅:')
34
+ console.log(`${profiles.length ? '已添加的订阅:' : '暂无已添加的订阅'}`)
38
35
  profiles.forEach(p => console.log(`- ${p}`))
39
36
  } else if (options.use) {
40
37
  try {
@@ -3,7 +3,7 @@ import path from 'path'
3
3
  import axios from 'axios'
4
4
  import { fileURLToPath } from 'url'
5
5
  import ora from 'ora'
6
- import { reloadConfig } from './api.js'
6
+ import { reloadConfig, isClashRunning } from './api.js'
7
7
 
8
8
  const __filename = fileURLToPath(import.meta.url)
9
9
  const __dirname = path.dirname(__filename)
@@ -47,9 +47,7 @@ export function getCurrentProfile() {
47
47
 
48
48
  export async function useProfile(name) {
49
49
  const source = path.join(PROFILES_DIR, `${name}.yaml`)
50
- if (!fs.existsSync(source)) {
51
- throw new Error(`配置文件 ${name} 不存在`)
52
- }
50
+ if (!fs.existsSync(source)) throw new Error(`配置文件 ${name} 不存在`)
53
51
 
54
52
  const spinner = ora(`正在切换到配置 ${name}...`).start()
55
53
 
@@ -58,11 +56,14 @@ export async function useProfile(name) {
58
56
  fs.writeFileSync(CURRENT_PROFILE_PATH, name)
59
57
 
60
58
  // 尝试热重载
61
- try {
62
- await reloadConfig(CONFIG_PATH)
63
- spinner.succeed('Clash 配置已切换并热重载生效')
64
- } catch (err) {
65
- // 忽略错误,可能是 Clash 未运行
66
- spinner.warn('配置已切换,但 Clash 未运行或无法连接,将在下次启动时生效')
59
+ if (await isClashRunning()) {
60
+ try {
61
+ await reloadConfig(CONFIG_PATH)
62
+ spinner.succeed('Clash 配置已切换并热重载生效')
63
+ } catch (err) {
64
+ spinner.warn(`配置已切换,但热重载失败: ${err.message}`)
65
+ }
66
+ } else {
67
+ spinner.succeed('配置已切换(Clash 未运行,将在下次启动时生效)')
67
68
  }
68
69
  }
package/package.json CHANGED
@@ -1,15 +1,18 @@
1
1
  {
2
2
  "name": "clash-kit",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "type": "module",
5
5
  "description": "A command-line interface for managing Clash configurations, subscriptions, and proxies.",
6
6
  "bin": {
7
+ "ck": "./bin/index.js",
7
8
  "clash": "./bin/index.js"
8
9
  },
9
10
  "files": [
10
11
  "bin",
11
12
  "lib",
12
13
  "index.js",
14
+ "country.mmdb",
15
+ "default.yaml",
13
16
  "package.json",
14
17
  "README.md"
15
18
  ],