@xx-in/tools 0.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.
Files changed (3) hide show
  1. package/README.md +88 -0
  2. package/dist/cli.js +2668 -0
  3. package/package.json +40 -0
package/dist/cli.js ADDED
@@ -0,0 +1,2668 @@
1
+ #!/usr/bin/env node
2
+
3
+ // mod.ts
4
+ import { Command } from "commander";
5
+ import process4 from "process";
6
+
7
+ // package.json
8
+ var package_default = {
9
+ name: "@xx-in/tools",
10
+ version: "0.0.1",
11
+ description: "A command-line tool to run in any system",
12
+ license: "MIT",
13
+ type: "module",
14
+ bin: {
15
+ xx: "dist/cli.js"
16
+ },
17
+ files: [
18
+ "dist"
19
+ ],
20
+ scripts: {
21
+ build: "tsup",
22
+ dev: "tsup --watch",
23
+ prepublishOnly: "npm run build"
24
+ },
25
+ engines: {
26
+ node: ">=18"
27
+ },
28
+ publishConfig: {
29
+ access: "public"
30
+ },
31
+ dependencies: {
32
+ "adm-zip": "^0.5.16",
33
+ commander: "^11.1.0",
34
+ "fast-glob": "^3.3.3",
35
+ "google-translate-api-x": "^10.7.3",
36
+ picocolors: "^1.1.1",
37
+ prettier: "^3.8.3",
38
+ tar: "^7.4.3",
39
+ trash: "^8.1.1"
40
+ },
41
+ devDependencies: {
42
+ "@types/adm-zip": "^0.5.7",
43
+ "@types/node": "^22.10.0",
44
+ tsup: "^8.4.0",
45
+ typescript: "^5.7.0"
46
+ }
47
+ };
48
+
49
+ // commands/completion.ts
50
+ import fs from "fs/promises";
51
+ import pc from "picocolors";
52
+ import { join } from "path";
53
+ var ZSH_SCRIPT = `
54
+ #compdef xx
55
+
56
+ _xx() {
57
+ local context state state_descr line
58
+ typeset -A opt_args
59
+
60
+ _arguments -C \\
61
+ '1:Cmd:->command' \\
62
+ '*::SubCmd:->args'
63
+
64
+ case $state in
65
+ command)
66
+ local -a subcommands
67
+ subcommands=(
68
+ 'completion:\u81EA\u52A8\u68C0\u6D4B\u5E76\u751F\u6210 Shell \u8865\u5168\u811A\u672C'
69
+ 'copy:\u590D\u5236\u6587\u4EF6\u6216\u76EE\u5F55\uFF08\u652F\u6301\u9012\u5F52\u590D\u5236\uFF09'
70
+ 'create:\u9012\u5F52\u521B\u5EFA\u6587\u4EF6\u6216\u76EE\u5F55'
71
+ 'format:\u4F7F\u7528 Prettier \u683C\u5F0F\u5316\u4EE3\u7801'
72
+ 'help:\u663E\u793A\u6307\u5B9A\u547D\u4EE4\u7684\u5E2E\u52A9\u4FE1\u606F'
73
+ 'install:\u81EA\u52A8\u5206\u53D1\u90E8\u7F72\u5B89\u88C5\u5305 (\u652F\u6301 AppImage\u3001Flatpak ID\u3001tar.gz\u3001deb\u3001rpm)'
74
+ 'ip:\u672C\u5730\u6D3B\u8DC3\u7F51\u5361\u53CA\u7F51\u5173\u4FA6\u6D4B'
75
+ 'list:\u5217\u51FA\u76EE\u5F55\u4E2D\u7684\u6240\u6709\u6587\u4EF6\u548C\u76EE\u5F55\uFF08\u542B\u9690\u85CF\u9879\uFF09'
76
+ 'move:\u79FB\u52A8\u6216\u91CD\u547D\u540D\u6587\u4EF6\u53CA\u76EE\u5F55'
77
+ 'open:\u5728\u7CFB\u7EDF\u6587\u4EF6\u7BA1\u7406\u5668\u4E2D\u6253\u5F00\u6307\u5B9A\u76EE\u5F55'
78
+ 'park:City189 Harbor \u79BB\u7EBF\u6253\u5305\u955C\u50CF\u4E0B\u8F7D\u5DE5\u5177'
79
+ 'proxy:\u7BA1\u7406\u7EC8\u7AEF\u4E34\u65F6\u4EE3\u7406 (proxy on [port] \u6216 proxy off)'
80
+ 'remove:\u5B89\u5168\u5730\u5C06\u6307\u5B9A\u7684\u6587\u4EF6\u6216\u76EE\u5F55\u79FB\u81F3\u7CFB\u7EDF\u56DE\u6536\u7AD9\uFF08\u652F\u6301\u901A\u914D\u7B26\u53CA\u591A\u9009\uFF09'
81
+ 'search:\u9012\u5F52\u641C\u7D22\u76EE\u5F55\u4E0B\u5305\u542B\u6307\u5B9A\u5173\u952E\u8BCD\u7684\u6587\u4EF6\u6216\u76EE\u5F55'
82
+ 'translate:\u7EC8\u7AEF\u7FFB\u8BD1\u5DE5\u5177'
83
+ 'uninstall:\u901A\u7528\u5E94\u7528\u5378\u8F7D\u5668\uFF08\u652F\u6301\u5305\u540D\u3001Flatpak\u3001Snap\u3001\u672C\u5730\u5305\u6216\u7EFF\u8272\u8F6F\u4EF6\uFF09'
84
+ 'unzip:\u89E3\u538B ZIP \u538B\u7F29\u5305'
85
+ 'upgrade:\u81EA\u52A8\u66F4\u65B0 xx \u547D\u4EE4\u884C\u5DE5\u5177\u81F3\u6700\u65B0\u7248\u672C'
86
+ 'zip:\u81EA\u52A8\u8FC7\u6EE4\u5E76\u6253\u5305\u4E3A ZIP'
87
+ )
88
+ _describe -t subcommands 'xx commands' subcommands
89
+ ;;
90
+ args)
91
+ case $line[1] in
92
+ copy)
93
+ _arguments \\
94
+ '1:Source:_files' \\
95
+ '2:Target:_files'
96
+ ;;
97
+ create)
98
+ _arguments \\
99
+ '*:Target Path:_files'
100
+ ;;
101
+ format)
102
+ _arguments \\
103
+ '*:Target Path:_files'
104
+ ;;
105
+ help)
106
+ local -a sub_cmds
107
+ sub_cmds=(
108
+ 'completion:\u81EA\u52A8\u68C0\u6D4B\u5E76\u751F\u6210 Shell \u8865\u5168\u811A\u672C'
109
+ 'copy:\u590D\u5236\u6587\u4EF6\u6216\u76EE\u5F55\uFF08\u652F\u6301\u9012\u5F52\u590D\u5236\uFF09'
110
+ 'create:\u9012\u5F52\u521B\u5EFA\u6587\u4EF6\u6216\u76EE\u5F55'
111
+ 'format:\u4F7F\u7528 Prettier \u683C\u5F0F\u5316\u4EE3\u7801'
112
+ 'install:\u81EA\u52A8\u5206\u53D1\u90E8\u7F72\u5B89\u88C5\u5305 (\u652F\u6301 AppImage\u3001Flatpak ID\u3001tar.gz\u3001deb\u3001rpm)'
113
+ 'ip:\u672C\u5730\u6D3B\u8DC3\u7F51\u5361\u53CA\u7F51\u5173\u4FA6\u6D4B'
114
+ 'list:\u5217\u51FA\u76EE\u5F55\u4E2D\u7684\u6240\u6709\u6587\u4EF6\u548C\u76EE\u5F55\uFF08\u542B\u9690\u85CF\u9879\uFF09'
115
+ 'move:\u79FB\u52A8\u6216\u91CD\u547D\u540D\u6587\u4EF6\u53CA\u76EE\u5F55'
116
+ 'open:\u5728\u7CFB\u7EDF\u6587\u4EF6\u7BA1\u7406\u5668\u4E2D\u6253\u5F00\u6307\u5B9A\u76EE\u5F55'
117
+ 'park:City189 Harbor \u79BB\u7EBF\u6253\u5305\u955C\u50CF\u4E0B\u8F7D\u5DE5\u5177'
118
+ 'proxy:\u7BA1\u7406\u7EC8\u7AEF\u4E34\u65F6\u4EE3\u7406 (proxy on [port] \u6216 proxy off)'
119
+ 'remove:\u5B89\u5168\u5730\u5C06\u6307\u5B9A\u7684\u6587\u4EF6\u6216\u76EE\u5F55\u79FB\u81F3\u7CFB\u7EDF\u56DE\u6536\u7AD9\uFF08\u652F\u6301\u901A\u914D\u7B26\u53CA\u591A\u9009\uFF09'
120
+ 'search:\u9012\u5F52\u641C\u7D22\u76EE\u5F55\u4E0B\u5305\u542B\u6307\u5B9A\u5173\u952E\u8BCD\u7684\u6587\u4EF6\u6216\u76EE\u5F55'
121
+ 'translate:\u7EC8\u7AEF\u7FFB\u8BD1\u5DE5\u5177'
122
+ 'uninstall:\u901A\u7528\u5E94\u7528\u5378\u8F7D\u5668\uFF08\u652F\u6301\u5305\u540D\u3001Flatpak\u3001Snap\u3001\u672C\u5730\u5305\u6216\u7EFF\u8272\u8F6F\u4EF6\uFF09'
123
+ 'unzip:\u89E3\u538B ZIP \u538B\u7F29\u5305'
124
+ 'upgrade:\u81EA\u52A8\u66F4\u65B0 xx \u547D\u4EE4\u884C\u5DE5\u5177\u81F3\u6700\u65B0\u7248\u672C'
125
+ 'zip:\u81EA\u52A8\u8FC7\u6EE4\u5E76\u6253\u5305\u4E3A ZIP'
126
+ )
127
+ _describe -t sub_cmds 'xx commands' sub_cmds
128
+ ;;
129
+ list|open)
130
+ _arguments \\
131
+ '*:Target Path:_files -/'
132
+ ;;
133
+ move)
134
+ _arguments \\
135
+ '1:Source:_files' \\
136
+ '2:Target:_files'
137
+ ;;
138
+ park)
139
+ _arguments \\
140
+ '-d[\u6307\u5B9A\u672C\u6B21\u4E0B\u8F7D\u4FDD\u5B58\u7684\u76EE\u5F55\u8DEF\u5F84]:directory:_files -/' \\
141
+ '-o[\u81EA\u5B9A\u4E49\u4FDD\u5B58\u7684\u6587\u4EF6\u540D]:filename:_files' \\
142
+ '-g[\u914D\u7F6E\u5168\u5C40\u9ED8\u8BA4\u4E0B\u8F7D\u76EE\u5F55]:directory:_files -/' \\
143
+ '*:Image Name:'
144
+ ;;
145
+ proxy)
146
+ _arguments \\
147
+ '1:Action:(on off)' \\
148
+ '2:Port:'
149
+ ;;
150
+ remove)
151
+ _arguments \\
152
+ '*:Target Path:_files'
153
+ ;;
154
+ translate)
155
+ _arguments \\
156
+ '-t[\u6307\u5B9A\u76EE\u6807\u8BED\u8A00 (\u9ED8\u8BA4 auto)]' \\
157
+ '*:Text:'
158
+ ;;
159
+ uninstall)
160
+ _arguments \\
161
+ '*:Package Path:_files'
162
+ ;;
163
+ unzip)
164
+ _arguments \\
165
+ '-d[\u6307\u5B9A\u89E3\u538B\u5230\u7684\u76EE\u6807\u76EE\u5F55\u8DEF\u5F84]:directory:_files -/' \\
166
+ '*:Zip File:_files -g "*.zip"'
167
+ ;;
168
+ zip)
169
+ _arguments \\
170
+ '*:Target Path:_files'
171
+ ;;
172
+ esac
173
+ ;;
174
+ esac
175
+ }
176
+
177
+ compdef _xx xx
178
+
179
+ # --- xx \u7EC8\u7AEF\u4EE3\u7406 Zsh \u62E6\u622A\u5305\u88C5\u51FD\u6570 ---
180
+ xx() {
181
+ if [[ "$1" == "proxy" ]]; then
182
+ if [[ -z "$2" ]]; then
183
+ if [[ -n "$http_proxy" || -n "$https_proxy" || -n "$all_proxy" || -n "$HTTP_PROXY" || -n "$HTTPS_PROXY" || -n "$ALL_PROXY" ]]; then
184
+ echo "\u{1F50D} [xx] \u7EC8\u7AEF\u5F53\u524D\u5DF2\u914D\u7F6E\u4EE3\u7406\uFF1A"
185
+ [[ -n "$http_proxy" ]] && echo " http_proxy = $http_proxy"
186
+ [[ -n "$https_proxy" ]] && echo " https_proxy = $https_proxy"
187
+ [[ -n "$all_proxy" ]] && echo " all_proxy = $all_proxy"
188
+ [[ -n "$HTTP_PROXY" ]] && echo " HTTP_PROXY = $HTTP_PROXY"
189
+ [[ -n "$HTTPS_PROXY" ]] && echo " HTTPS_PROXY = $HTTPS_PROXY"
190
+ [[ -n "$ALL_PROXY" ]] && echo " ALL_PROXY = $ALL_PROXY"
191
+ else
192
+ echo "\u{1F50D} [xx] \u7EC8\u7AEF\u5F53\u524D\u672A\u914D\u7F6E\u4EFB\u4F55\u4EE3\u7406 (\u76F4\u8FDE\u6A21\u5F0F)"
193
+ fi
194
+ elif [[ "$2" == "on" ]]; then
195
+ local port="\${3:-7890}"
196
+ export http_proxy="http://127.0.0.1:$port"
197
+ export https_proxy="http://127.0.0.1:$port"
198
+ export all_proxy="socks5://127.0.0.1:$port"
199
+ export HTTP_PROXY="http://127.0.0.1:$port"
200
+ export HTTPS_PROXY="http://127.0.0.1:$port"
201
+ export ALL_PROXY="socks5://127.0.0.1:$port"
202
+ echo "\u2714 [xx] \u5DF2\u5F00\u542F\u7EC8\u7AEF\u4E34\u65F6\u4EE3\u7406: 127.0.0.1:$port"
203
+ elif [[ "$2" == "off" ]]; then
204
+ unset http_proxy https_proxy all_proxy HTTP_PROXY HTTPS_PROXY ALL_PROXY
205
+ echo "\u2714 [xx] \u5DF2\u5173\u95ED\u7EC8\u7AEF\u4E34\u65F6\u4EE3\u7406"
206
+ else
207
+ command xx "$@"
208
+ fi
209
+ else
210
+ command xx "$@"
211
+ fi
212
+ }
213
+ `;
214
+ var BASH_SCRIPT = `
215
+ _xx_completion() {
216
+ local cur prev opts
217
+ COMPREPLY=()
218
+ cur="\${COMP_WORDS[COMP_CWORD]}"
219
+ prev="\${COMP_WORDS[COMP_CWORD-1]}"
220
+ opts="completion copy create format help install ip list move open park proxy remove search translate uninstall unzip upgrade zip"
221
+
222
+ if [[ \${COMP_CWORD} -eq 1 ]] ; then
223
+ COMPREPLY=( $(compgen -W "\${opts}" -- \${cur}) )
224
+ return 0
225
+ fi
226
+
227
+ case "\${COMP_WORDS[1]}" in
228
+ park)
229
+ local sub_opts="-d -o -g"
230
+ COMPREPLY=( $(compgen -W "\${sub_opts}" -- \${cur}) )
231
+ return 0
232
+ ;;
233
+ proxy)
234
+ if [[ \${COMP_CWORD} -eq 2 ]] ; then
235
+ local sub_opts="on off"
236
+ COMPREPLY=( $(compgen -W "\${sub_opts}" -- \${cur}) )
237
+ return 0
238
+ fi
239
+ ;;
240
+ unzip)
241
+ local sub_opts="-d"
242
+ COMPREPLY=( $(compgen -W "\${sub_opts}" -- \${cur}) )
243
+ return 0
244
+ ;;
245
+ translate)
246
+ local sub_opts="-t"
247
+ COMPREPLY=( $(compgen -W "\${sub_opts}" -- \${cur}) )
248
+ return 0
249
+ ;;
250
+ help)
251
+ local sub_opts="completion copy create format ip list move open park proxy remove search translate uninstall unzip upgrade zip"
252
+ COMPREPLY=( $(compgen -W "\${sub_opts}" -- \${cur}) )
253
+ return 0
254
+ ;;
255
+ esac
256
+
257
+ COMPREPLY=( $(compgen -f -- "\${cur}") )
258
+ }
259
+ complete -o filenames -o default -o bashdefault -F _xx_completion xx
260
+
261
+ # --- xx \u7EC8\u7AEF\u4EE3\u7406 Bash \u62E6\u622A\u5305\u88C5\u51FD\u6570 ---
262
+ xx() {
263
+ if [[ "$1" == "proxy" ]]; then
264
+ if [[ -z "$2" ]]; then
265
+ if [[ -n "$http_proxy" || -n "$https_proxy" || -n "$all_proxy" || -n "$HTTP_PROXY" || -n "$HTTPS_PROXY" || -n "$ALL_PROXY" ]]; then
266
+ echo "\u{1F50D} [xx] \u7EC8\u7AEF\u5F53\u524D\u5DF2\u914D\u7F6E\u4EE3\u7406\uFF1A"
267
+ [[ -n "$http_proxy" ]] && echo " http_proxy = $http_proxy"
268
+ [[ -n "$https_proxy" ]] && echo " https_proxy = $https_proxy"
269
+ [[ -n "$all_proxy" ]] && echo " all_proxy = $all_proxy"
270
+ [[ -n "$HTTP_PROXY" ]] && echo " HTTP_PROXY = $HTTP_PROXY"
271
+ [[ -n "$HTTPS_PROXY" ]] && echo " HTTPS_PROXY = $HTTPS_PROXY"
272
+ [[ -n "$ALL_PROXY" ]] && echo " ALL_PROXY = $ALL_PROXY"
273
+ else
274
+ echo "\u{1F50D} [xx] \u7EC8\u7AEF\u5F53\u524D\u672A\u914D\u7F6E\u4EFB\u4F55\u4EE3\u7406 (\u76F4\u8FDE\u6A21\u5F0F)"
275
+ fi
276
+ elif [[ "$2" == "on" ]]; then
277
+ local port="\${3:-7890}"
278
+ export http_proxy="http://127.0.0.1:$port"
279
+ export https_proxy="http://127.0.0.1:$port"
280
+ export all_proxy="socks5://127.0.0.1:$port"
281
+ export HTTP_PROXY="http://127.0.0.1:$port"
282
+ export HTTPS_PROXY="http://127.0.0.1:$port"
283
+ export ALL_PROXY="socks5://127.0.0.1:$port"
284
+ echo "\u2714 [xx] \u5DF2\u5F00\u542F\u7EC8\u7AEF\u4E34\u65F6\u4EE3\u7406: 127.0.0.1:$port"
285
+ elif [[ "$2" == "off" ]]; then
286
+ unset http_proxy https_proxy all_proxy HTTP_PROXY HTTPS_PROXY ALL_PROXY
287
+ echo "\u2714 [xx] \u5DF2\u5173\u95ED\u7EC8\u7AEF\u4E34\u65F6\u4EE3\u7406"
288
+ else
289
+ command xx "$@"
290
+ fi
291
+ else
292
+ command xx "$@"
293
+ fi
294
+ }
295
+ `;
296
+ var POWERSHELL_SCRIPT = `
297
+ $xx_completer = {
298
+ param($wordToComplete, $commandAst, $cursorPosition)
299
+ $commands = @("completion", "copy", "create", "format", "help", "install", "ip", "list", "move", "open", "park", "proxy", "remove", "search", "translate", "uninstall", "unzip", "upgrade", "zip")
300
+ $sub_opts = @{
301
+ "park" = @("-d", "-o", "-g")
302
+ "proxy" = @("on", "off")
303
+ "unzip" = @("-d")
304
+ "translate" = @("-t")
305
+ "help" = @("completion", "copy", "create", "format", "ip", "list", "move", "open", "park", "proxy", "remove", "search", "translate", "uninstall", "unzip", "upgrade", "zip")
306
+ }
307
+ $tokens = $commandAst.Elements | ForEach-Object { $_.Value } | Where-Object { $_ -ne $null }
308
+ $tokenCount = $tokens.Count
309
+
310
+ if ($tokenCount -le 2) {
311
+ $commands | Where-Object { $_ -like "$wordToComplete*" } | ForEach-Object {
312
+ [System.Management.Automation.CompletionResult]::new($_, $_, 'Command', $_)
313
+ }
314
+ } else {
315
+ $subCmd = $tokens[1]
316
+ if ($sub_opts.ContainsKey($subCmd)) {
317
+ $opts = $sub_opts[$subCmd]
318
+ $opts | Where-Object { $_ -like "$wordToComplete*" } | ForEach-Object {
319
+ [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterName', $_)
320
+ }
321
+ }
322
+ }
323
+ }
324
+ Register-ArgumentCompleter -CommandName 'xx' -ScriptBlock $xx_completer
325
+
326
+ # --- xx \u7EC8\u7AEF\u4EE3\u7406 PowerShell \u62E6\u622A\u5305\u88C5\u51FD\u6570 ---
327
+ function xx {
328
+ if ($args[0] -eq "proxy") {
329
+ if (-not $args[1]) {
330
+ if ($env:http_proxy -or $env:https_proxy -or $env:all_proxy -or $env:HTTP_PROXY -or $env:HTTPS_PROXY -or $env:ALL_PROXY) {
331
+ Write-Host "\u{1F50D} [xx] \u7EC8\u7AEF\u5F53\u524D\u5DF2\u914D\u7F6E\u4EE3\u7406\uFF1A" -ForegroundColor Yellow
332
+ if ($env:http_proxy) { Write-Host " http_proxy = $env:http_proxy" }
333
+ if ($env:https_proxy) { Write-Host " https_proxy = $env:https_proxy" }
334
+ if ($env:all_proxy) { Write-Host " all_proxy = $env:all_proxy" }
335
+ if ($env:HTTP_PROXY) { Write-Host " HTTP_PROXY = $env:HTTP_PROXY" }
336
+ if ($env:HTTPS_PROXY) { Write-Host " HTTPS_PROXY = $env:HTTPS_PROXY" }
337
+ if ($env:ALL_PROXY) { Write-Host " ALL_PROXY = $env:ALL_PROXY" }
338
+ } else {
339
+ Write-Host "\u{1F50D} [xx] \u7EC8\u7AEF\u5F53\u524D\u672A\u914D\u7F6E\u4EFB\u4F55\u4EE3\u7406 (\u76F4\u8FDE\u6A21\u5F0F)" -ForegroundColor Green
340
+ }
341
+ } elseif ($args[1] -eq "on") {
342
+ $port = if ($args[2]) { $args[2] } else { "7890" }
343
+ $env:http_proxy = "http://127.0.0.1:$port"
344
+ $env:https_proxy = "http://127.0.0.1:$port"
345
+ $env:all_proxy = "socks5://127.0.0.1:$port"
346
+ $env:HTTP_PROXY = "http://127.0.0.1:$port"
347
+ $env:HTTPS_PROXY = "http://127.0.0.1:$port"
348
+ $env:ALL_PROXY = "socks5://127.0.0.1:$port"
349
+ Write-Host "\u2714 [xx] \u5DF2\u5F00\u542F\u7EC8\u7AEF\u4E34\u65F6\u4EE3\u7406: 127.0.0.1:$port" -ForegroundColor Green
350
+ } elseif ($args[1] -eq "off") {
351
+ Remove-Item env:http_proxy -ErrorAction SilentlyContinue
352
+ Remove-Item env:https_proxy -ErrorAction SilentlyContinue
353
+ Remove-Item env:all_proxy -ErrorAction SilentlyContinue
354
+ Remove-Item env:HTTP_PROXY -ErrorAction SilentlyContinue
355
+ Remove-Item env:HTTPS_PROXY -ErrorAction SilentlyContinue
356
+ Remove-Item env:ALL_PROXY -ErrorAction SilentlyContinue
357
+ Write-Host "\u2714 [xx] \u5DF2\u5173\u95ED\u7EC8\u7AEF\u4E34\u65F6\u4EE3\u7406" -ForegroundColor Green
358
+ } else {
359
+ & (Get-Command xx -CommandType Application) @args
360
+ }
361
+ } else {
362
+ & (Get-Command xx -CommandType Application) @args
363
+ }
364
+ }
365
+ `;
366
+ async function autoInstallCompletion() {
367
+ const osType2 = process.platform;
368
+ const home = process.env["HOME"] || process.env["USERPROFILE"] || "";
369
+ if (!home) {
370
+ console.error(pc.red("\u274C \u9519\u8BEF: \u65E0\u6CD5\u5B9A\u4F4D\u5230\u7528\u6237\u7684\u6839\u76EE\u5F55\u3002"));
371
+ return;
372
+ }
373
+ if (osType2 === "win32") {
374
+ const completionPath = join(home, ".xx_completion_xx.ps1");
375
+ try {
376
+ const bom = new Uint8Array([239, 187, 191]);
377
+ const contentBytes = new TextEncoder().encode(POWERSHELL_SCRIPT.trim());
378
+ const mergedBytes = new Uint8Array(bom.length + contentBytes.length);
379
+ mergedBytes.set(bom);
380
+ mergedBytes.set(contentBytes, bom.length);
381
+ await fs.writeFile(completionPath, mergedBytes);
382
+ console.log(
383
+ pc.green(
384
+ `\u2714 \u5DF2\u521B\u5EFA\u5E76\u8986\u76D6 PowerShell \u8865\u5168\u811A\u672C (UTF-8 BOM): ${pc.bold(completionPath)}`
385
+ )
386
+ );
387
+ const profileDirs = [
388
+ join(home, "Documents", "WindowsPowerShell"),
389
+ join(home, "Documents", "PowerShell"),
390
+ join(home, "OneDrive", "Documents", "WindowsPowerShell"),
391
+ join(home, "OneDrive", "Documents", "PowerShell")
392
+ ];
393
+ let isAdded = false;
394
+ const sourceLine = `. "$HOME\\.xx_completion_xx.ps1"`;
395
+ for (const dir of profileDirs) {
396
+ try {
397
+ const profilePath = join(dir, "Microsoft.PowerShell_profile.ps1");
398
+ await fs.mkdir(dir, { recursive: true });
399
+ let content = "";
400
+ try {
401
+ content = await fs.readFile(profilePath, "utf-8");
402
+ } catch {
403
+ }
404
+ if (!content.includes(sourceLine)) {
405
+ const separator = content.endsWith("\n") || content === "" ? "" : "\n";
406
+ await fs.writeFile(
407
+ profilePath,
408
+ `${content}${separator}${sourceLine}
409
+ `
410
+ );
411
+ console.log(
412
+ pc.green(`\u2714 \u5DF2\u5728\u914D\u7F6E\u6587\u4EF6\u4E2D\u6CE8\u518C\u8865\u5168\u9879: ${pc.bold(profilePath)}`)
413
+ );
414
+ } else {
415
+ console.log(pc.dim(`\u2796 \u8865\u5168\u6CE8\u518C\u9879\u5DF2\u5B58\u5728: ${profilePath}`));
416
+ }
417
+ isAdded = true;
418
+ } catch {
419
+ }
420
+ }
421
+ if (isAdded) {
422
+ console.log(
423
+ pc.magenta(
424
+ `
425
+ \u2728 \u8865\u5168\u81EA\u52A8\u914D\u7F6E\u6210\u529F! \u8BF7\u91CD\u542F PowerShell \u7EC8\u7AEF\u4EE5\u6FC0\u6D3B Tab \u952E\u81EA\u52A8\u63D0\u793A\u3002`
426
+ )
427
+ );
428
+ }
429
+ } catch (err) {
430
+ console.error(
431
+ pc.red("\u274C \u81EA\u52A8\u914D\u7F6E\u5931\u8D25:"),
432
+ err instanceof Error ? err.message : err
433
+ );
434
+ }
435
+ } else {
436
+ const shellEnv = process.env["SHELL"] || "";
437
+ let shell = "zsh";
438
+ let profileName = ".zshrc";
439
+ let scriptContent = ZSH_SCRIPT;
440
+ if (osType2 === "linux") {
441
+ shell = "bash";
442
+ profileName = ".bashrc";
443
+ scriptContent = BASH_SCRIPT;
444
+ }
445
+ if (shellEnv.includes("zsh")) {
446
+ shell = "zsh";
447
+ profileName = ".zshrc";
448
+ scriptContent = ZSH_SCRIPT;
449
+ } else if (shellEnv.includes("bash")) {
450
+ shell = "bash";
451
+ profileName = ".bashrc";
452
+ scriptContent = BASH_SCRIPT;
453
+ }
454
+ const completionPath = join(home, ".xx_completion_xx");
455
+ const profilePath = join(home, profileName);
456
+ try {
457
+ await fs.writeFile(completionPath, scriptContent.trim());
458
+ console.log(
459
+ pc.green(
460
+ `\u2714 \u5DF2\u521B\u5EFA\u5E76\u8986\u76D6 ${shell} \u8865\u5168\u811A\u672C: ${pc.bold(completionPath)}`
461
+ )
462
+ );
463
+ let profileContent = "";
464
+ try {
465
+ profileContent = await fs.readFile(profilePath, "utf-8");
466
+ } catch {
467
+ }
468
+ const sourceLine = `source ${completionPath}`;
469
+ if (!profileContent.includes(sourceLine)) {
470
+ const separator = profileContent.endsWith("\n") || profileContent === "" ? "" : "\n";
471
+ await fs.writeFile(
472
+ profilePath,
473
+ `${profileContent}${separator}${sourceLine}
474
+ `
475
+ );
476
+ console.log(
477
+ pc.green(`\u2714 \u5DF2\u5728 ${pc.bold(profileName)} \u914D\u7F6E\u6587\u4EF6\u672B\u5C3E\u8FFD\u52A0\u52A0\u8F7D\u4EE3\u7801\u3002`)
478
+ );
479
+ } else {
480
+ console.log(pc.dim(`\u2796 ${profileName} \u4E2D\u5DF2\u5B58\u5728\u52A0\u8F7D\u4EE3\u7801\uFF0C\u8DF3\u8FC7\u8FFD\u52A0\u3002`));
481
+ }
482
+ console.log(
483
+ pc.magenta(
484
+ `
485
+ \u2728 \u8865\u5168\u81EA\u52A8\u914D\u7F6E\u6210\u529F! \u8BF7\u6267\u884C ${pc.bold(
486
+ pc.yellow(`source ~/${profileName}`)
487
+ )} \u6216\u91CD\u65B0\u6253\u5F00\u7EC8\u7AEF\u4EE5\u6FC0\u6D3B Tab \u63D0\u793A\u3002`
488
+ )
489
+ );
490
+ } catch (err) {
491
+ console.error(
492
+ pc.red("\u274C \u81EA\u52A8\u914D\u7F6E\u5931\u8D25:"),
493
+ err instanceof Error ? err.message : err
494
+ );
495
+ }
496
+ }
497
+ }
498
+ function registerCompletionCommand(program2) {
499
+ program2.command("completion [shell]").description(
500
+ "\u81EA\u52A8\u5B89\u88C5\u6216\u751F\u6210 Shell \u547D\u4EE4\u884C\u81EA\u52A8\u8865\u5168\u811A\u672C (\u652F\u6301 bash, zsh, powershell)"
501
+ ).action(async (shell) => {
502
+ if (!shell) {
503
+ console.log(pc.cyan("\u{1F916} \u6B63\u5728\u4E3A\u60A8\u81EA\u52A8\u68C0\u6D4B\u73AF\u5883\u5E76\u914D\u7F6E\u547D\u4EE4\u884C\u81EA\u52A8\u8865\u5168..."));
504
+ await autoInstallCompletion();
505
+ } else {
506
+ const target = shell.toLowerCase();
507
+ if (target === "zsh") {
508
+ console.log(ZSH_SCRIPT.trim());
509
+ } else if (target === "bash") {
510
+ console.log(BASH_SCRIPT.trim());
511
+ } else if (target === "powershell" || target === "ps1" || target === "pwsh") {
512
+ console.log(POWERSHELL_SCRIPT.trim());
513
+ } else {
514
+ console.error(
515
+ pc.red(
516
+ `\u274C \u9519\u8BEF: \u6682\u4E0D\u652F\u6301\u7684 Shell \u7C7B\u578B '${shell}'\u3002\u53EF\u9009\u503C: bash, zsh, powershell`
517
+ )
518
+ );
519
+ }
520
+ }
521
+ });
522
+ }
523
+
524
+ // utils/spawn.ts
525
+ import { spawn, spawnSync } from "child_process";
526
+ import { platform } from "process";
527
+ var osType = platform;
528
+ function isNotFoundError(err) {
529
+ return err instanceof Error && "code" in err && err.code === "ENOENT";
530
+ }
531
+ function isCommandAvailable(cmd) {
532
+ const whichCmd = osType === "win32" ? "where" : "which";
533
+ const result = spawnSync(whichCmd, [cmd], { stdio: "ignore" });
534
+ return result.status === 0;
535
+ }
536
+ function runCommand(cmd, args, options = {}) {
537
+ const stdio = options.stdio ?? "pipe";
538
+ return new Promise((resolve14, reject) => {
539
+ const child = spawn(cmd, args, { stdio });
540
+ if (stdio === "inherit" || stdio === "ignore") {
541
+ child.on("error", reject);
542
+ child.on("close", (code) => {
543
+ resolve14({
544
+ success: code === 0,
545
+ code,
546
+ stdout: Buffer.alloc(0),
547
+ stderr: Buffer.alloc(0)
548
+ });
549
+ });
550
+ return;
551
+ }
552
+ const stdoutChunks = [];
553
+ const stderrChunks = [];
554
+ child.stdout?.on("data", (chunk) => stdoutChunks.push(chunk));
555
+ child.stderr?.on("data", (chunk) => stderrChunks.push(chunk));
556
+ child.on("error", reject);
557
+ child.on("close", (code) => {
558
+ resolve14({
559
+ success: code === 0,
560
+ code,
561
+ stdout: Buffer.concat(stdoutChunks),
562
+ stderr: Buffer.concat(stderrChunks)
563
+ });
564
+ });
565
+ });
566
+ }
567
+ async function spawnCommand(cmd, args) {
568
+ const result = await runCommand(cmd, args, { stdio: "inherit" });
569
+ return { success: result.success, code: result.code };
570
+ }
571
+ function decodeOutput(buf) {
572
+ return buf.toString("utf-8");
573
+ }
574
+
575
+ // commands/copy.ts
576
+ import fs2 from "fs/promises";
577
+ import pc2 from "picocolors";
578
+ import { dirname, resolve, join as join2, basename } from "path";
579
+ async function copyRecursive(src, dest) {
580
+ const fileInfo = await fs2.stat(src);
581
+ if (fileInfo.isDirectory()) {
582
+ await fs2.mkdir(dest, { recursive: true });
583
+ for (const entry of await fs2.readdir(src, { withFileTypes: true })) {
584
+ await copyRecursive(join2(src, entry.name), join2(dest, entry.name));
585
+ }
586
+ } else if (fileInfo.isFile()) {
587
+ await fs2.mkdir(dirname(dest), { recursive: true });
588
+ await fs2.copyFile(src, dest);
589
+ }
590
+ }
591
+ function registerCopyCommand(program2) {
592
+ program2.command("copy <source> <target>").description("\u590D\u5236\u6587\u4EF6\u6216\u76EE\u5F55\uFF08\u652F\u6301\u9012\u5F52\u590D\u5236\uFF09").action(async (source, target) => {
593
+ if (!source || !target) {
594
+ console.error(pc2.red("\u274C \u8BF7\u63D0\u4F9B\u6E90\u8DEF\u5F84\u548C\u76EE\u6807\u8DEF\u5F84"));
595
+ return;
596
+ }
597
+ const absSource = resolve(process.cwd(), source);
598
+ const absTarget = resolve(process.cwd(), target);
599
+ try {
600
+ await fs2.stat(absSource);
601
+ let finalTarget = absTarget;
602
+ try {
603
+ const targetStat = await fs2.stat(absTarget);
604
+ if (targetStat.isDirectory()) {
605
+ finalTarget = join2(absTarget, basename(absSource));
606
+ }
607
+ } catch {
608
+ }
609
+ console.log(pc2.cyan(`\u{1F4E6} \u6B63\u5728\u590D\u5236: ${source} \u27A1\uFE0F ${target}...`));
610
+ await copyRecursive(absSource, finalTarget);
611
+ console.log(pc2.green(`\u2728 \u590D\u5236\u6210\u529F: ${source} \u27A1\uFE0F ${target}`));
612
+ } catch (err) {
613
+ if (isNotFoundError(err)) {
614
+ console.error(pc2.red(`\u274C \u9519\u8BEF: \u6E90\u8DEF\u5F84\u4E0D\u5B58\u5728: ${absSource}`));
615
+ } else {
616
+ console.error(
617
+ pc2.red("\u274C \u590D\u5236\u5931\u8D25:"),
618
+ err instanceof Error ? err.message : err
619
+ );
620
+ }
621
+ }
622
+ });
623
+ }
624
+
625
+ // commands/create.ts
626
+ import fs3 from "fs/promises";
627
+ import pc3 from "picocolors";
628
+ import { dirname as dirname2, resolve as resolve2 } from "path";
629
+ function registerCreateCommand(program2) {
630
+ program2.command("create <paths...>").description("\u9012\u5F52\u521B\u5EFA\u591A\u4E2A\u6587\u4EF6\u6216\u76EE\u5F55\uFF08\u4EE5 / \u7ED3\u5C3E\u5219\u521B\u5EFA\u76EE\u5F55\uFF0C\u5426\u5219\u521B\u5EFA\u6587\u4EF6\uFF09").action(async (paths) => {
631
+ if (!paths || paths.length === 0) {
632
+ console.error(pc3.red("\u274C \u8BF7\u63D0\u4F9B\u81F3\u5C11\u4E00\u4E2A\u8981\u521B\u5EFA\u7684\u8DEF\u5F84"));
633
+ return;
634
+ }
635
+ for (const targetPath of paths) {
636
+ const isDir = targetPath.endsWith("/") || targetPath.endsWith("\\");
637
+ const absolutePath = resolve2(process.cwd(), targetPath);
638
+ try {
639
+ if (isDir) {
640
+ await fs3.mkdir(absolutePath, { recursive: true });
641
+ console.log(pc3.green(`\u2728 \u6210\u529F\u9012\u5F52\u521B\u5EFA\u76EE\u5F55: ${absolutePath}`));
642
+ } else {
643
+ const parentDir = dirname2(absolutePath);
644
+ await fs3.mkdir(parentDir, { recursive: true });
645
+ try {
646
+ await fs3.stat(absolutePath);
647
+ console.log(pc3.yellow(`\u26A0\uFE0F \u6587\u4EF6\u5DF2\u5B58\u5728: ${absolutePath}`));
648
+ } catch (err) {
649
+ if (isNotFoundError(err)) {
650
+ await fs3.writeFile(absolutePath, "", "utf-8");
651
+ console.log(pc3.green(`\u2728 \u6210\u529F\u521B\u5EFA\u6587\u4EF6: ${absolutePath}`));
652
+ } else {
653
+ throw err;
654
+ }
655
+ }
656
+ }
657
+ } catch (err) {
658
+ console.error(
659
+ pc3.red(`\u274C \u521B\u5EFA\u5931\u8D25 [${targetPath}]:`),
660
+ err instanceof Error ? err.message : err
661
+ );
662
+ }
663
+ }
664
+ });
665
+ }
666
+
667
+ // commands/format.ts
668
+ import fs4 from "fs/promises";
669
+ import pc4 from "picocolors";
670
+ import { resolve as resolve3, join as join3 } from "path";
671
+ import { getFileInfo, resolveConfig, format } from "prettier";
672
+ async function getFilesRecursively(dirPath) {
673
+ const files = [];
674
+ const entries = await fs4.readdir(dirPath, { withFileTypes: true });
675
+ for await (const entry of entries) {
676
+ const fullPath = join3(dirPath, entry.name);
677
+ if (entry.name === "node_modules" || entry.name === ".git" || entry.name === "dist") {
678
+ continue;
679
+ }
680
+ if (entry.isDirectory()) {
681
+ files.push(...await getFilesRecursively(fullPath));
682
+ } else if (entry.isFile()) {
683
+ files.push(fullPath);
684
+ }
685
+ }
686
+ return files;
687
+ }
688
+ function registerFormatCommand(program2) {
689
+ program2.command("format [path]").description("\u4F7F\u7528 Prettier \u81EA\u52A8\u683C\u5F0F\u5316\u4EE3\u7801\u6587\u4EF6\u6216\u76EE\u5F55\u4E2D\u7684\u6240\u6709\u6587\u4EF6").action(async (targetPath) => {
690
+ const inputPath = targetPath || ".";
691
+ const absolutePath = resolve3(process.cwd(), inputPath);
692
+ let targetFiles = [];
693
+ try {
694
+ const stat = await fs4.stat(absolutePath);
695
+ if (stat.isDirectory()) {
696
+ console.log(pc4.cyan(`\u{1F50D} \u6B63\u5728\u626B\u63CF\u76EE\u5F55\u4E2D\u7684\u6587\u4EF6: ${absolutePath}...`));
697
+ targetFiles = await getFilesRecursively(absolutePath);
698
+ } else if (stat.isFile()) {
699
+ targetFiles = [absolutePath];
700
+ }
701
+ } catch {
702
+ console.error(pc4.red(`\u274C \u9519\u8BEF: \u627E\u4E0D\u5230\u6307\u5B9A\u7684\u8DEF\u5F84 '${inputPath}'\u3002`));
703
+ return;
704
+ }
705
+ if (targetFiles.length === 0) {
706
+ console.log(pc4.yellow("\u26A0\uFE0F \u672A\u627E\u5230\u4EFB\u4F55\u53EF\u4F9B\u683C\u5F0F\u5316\u7684\u6587\u4EF6\u3002"));
707
+ return;
708
+ }
709
+ console.log(
710
+ pc4.cyan(`\u2728 \u5F00\u59CB\u4F7F\u7528 Prettier \u683C\u5F0F\u5316 ${targetFiles.length} \u4E2A\u6587\u4EF6...`)
711
+ );
712
+ let successCount = 0;
713
+ let errorCount = 0;
714
+ let ignoredCount = 0;
715
+ for (const filePath of targetFiles) {
716
+ try {
717
+ const fileInfo = await getFileInfo(filePath);
718
+ if (!fileInfo || fileInfo.ignored || !fileInfo.inferredParser) {
719
+ ignoredCount++;
720
+ continue;
721
+ }
722
+ const content = await fs4.readFile(filePath, "utf-8");
723
+ const config = await resolveConfig(filePath) || {};
724
+ const formatted = await format(content, {
725
+ // 👈 直接调用 format
726
+ ...config,
727
+ filepath: filePath
728
+ // 关键:指定 filepath 以便 Prettier 自动加载对应的 Parser
729
+ });
730
+ if (content !== formatted) {
731
+ await fs4.writeFile(filePath, formatted, "utf-8");
732
+ console.log(pc4.green(`\u2714 \u5DF2\u683C\u5F0F\u5316: ${filePath}`));
733
+ } else {
734
+ console.log(pc4.dim(`\u2796 \u65E0\u9700\u4FEE\u6539: ${filePath}`));
735
+ }
736
+ successCount++;
737
+ } catch (err) {
738
+ errorCount++;
739
+ console.error(
740
+ pc4.red(`\u274C \u683C\u5F0F\u5316\u5931\u8D25 [${filePath}]:`),
741
+ err instanceof Error ? err.message : err
742
+ );
743
+ }
744
+ }
745
+ console.log(
746
+ pc4.cyan(
747
+ `
748
+ \u{1F3C1} \u683C\u5F0F\u5316\u6D41\u7A0B\u7ED3\u675F! \u6210\u529F: ${pc4.bold(successCount)} \u4E2A, \u5FFD\u7565/\u4E0D\u9002\u914D: ${pc4.bold(ignoredCount)} \u4E2A, \u5931\u8D25: ${pc4.bold(errorCount)} \u4E2A\u3002`
749
+ )
750
+ );
751
+ });
752
+ }
753
+
754
+ // commands/install.ts
755
+ import fs5 from "fs/promises";
756
+ import pc5 from "picocolors";
757
+ import { resolve as resolve4, join as join4, basename as basename2 } from "path";
758
+ function getHomeDir() {
759
+ return process.env["HOME"] || process.env["USERPROFILE"] || process.cwd();
760
+ }
761
+ async function createShortcut(targetPath) {
762
+ const home = getHomeDir();
763
+ const applicationsDir = join4(home, ".local/share/applications");
764
+ let name = "";
765
+ let execLine = "";
766
+ let desktopFileName = "";
767
+ const isFlatpak = !targetPath.includes("/") && !targetPath.includes("\\") && targetPath.split(".").length >= 3;
768
+ if (isFlatpak) {
769
+ const segments = targetPath.split(".");
770
+ name = segments[segments.length - 1];
771
+ execLine = `flatpak run ${targetPath}`;
772
+ desktopFileName = `flatpak-${targetPath}.desktop`;
773
+ } else {
774
+ const absolutePath = resolve4(process.cwd(), targetPath);
775
+ try {
776
+ const stat = await fs5.stat(absolutePath);
777
+ if (!stat.isFile()) {
778
+ console.error(pc5.red(`\u274C \u9519\u8BEF: '${targetPath}' \u4E0D\u662F\u4E00\u4E2A\u6709\u6548\u7684\u6587\u4EF6\u3002`));
779
+ return;
780
+ }
781
+ } catch {
782
+ console.error(pc5.red(`\u274C \u9519\u8BEF: \u627E\u4E0D\u5230\u6587\u4EF6 '${targetPath}'\u3002`));
783
+ return;
784
+ }
785
+ const isAppImage = targetPath.toLowerCase().endsWith(".appimage");
786
+ name = basename2(absolutePath, isAppImage ? ".AppImage" : "");
787
+ try {
788
+ await fs5.chmod(absolutePath, 493);
789
+ } catch {
790
+ }
791
+ execLine = isAppImage ? `"${absolutePath}" --no-sandbox` : `"${absolutePath}"`;
792
+ desktopFileName = `${name.replace(/\s+/g, "-").toLowerCase()}.desktop`;
793
+ }
794
+ const desktopFilePath = join4(applicationsDir, desktopFileName);
795
+ const desktopContent = `[Desktop Entry]
796
+ Name=${name}
797
+ Exec=${execLine}
798
+ Type=Application
799
+ Terminal=false
800
+ Categories=Utility;
801
+ `;
802
+ try {
803
+ await fs5.mkdir(applicationsDir, { recursive: true });
804
+ await fs5.writeFile(desktopFilePath, desktopContent, "utf-8");
805
+ console.log(pc5.green(`\u2714 \u5FEB\u6377\u65B9\u5F0F\u5DF2\u521B\u5EFA: ${desktopFilePath}`));
806
+ console.log(pc5.dim(`\u542F\u52A8\u547D\u4EE4: ${execLine}`));
807
+ } catch (err) {
808
+ console.error(
809
+ pc5.red("\u274C \u521B\u5EFA\u5FEB\u6377\u65B9\u5F0F\u5931\u8D25:"),
810
+ err instanceof Error ? err.message : err
811
+ );
812
+ }
813
+ }
814
+ async function installAppImage(absPath) {
815
+ const home = getHomeDir();
816
+ const greenAppDir = join4(home, "GreenApp");
817
+ const fileName = basename2(absPath);
818
+ const destPath = join4(greenAppDir, fileName);
819
+ const isAppImage = fileName.toLowerCase().endsWith(".appimage");
820
+ const appNameClean = basename2(absPath, isAppImage ? ".AppImage" : "");
821
+ try {
822
+ await fs5.mkdir(greenAppDir, { recursive: true });
823
+ console.log(
824
+ pc5.cyan(`\u{1F4E6} \u6B63\u5728\u5C06 AppImage \u90E8\u7F72\u81F3\u7EFF\u8272\u8F6F\u4EF6\u76EE\u5F55: ${destPath}...`)
825
+ );
826
+ await fs5.copyFile(absPath, destPath);
827
+ await fs5.chmod(destPath, 493);
828
+ await createShortcut(destPath);
829
+ console.log(pc5.green(`\u2728 AppImage \u90E8\u7F72\u5B8C\u6210\uFF01`));
830
+ console.log(
831
+ pc5.green(
832
+ `
833
+ \u2728 \u5B89\u88C5\u6210\u529F\uFF01\u8BE5\u7EFF\u8272\u8F6F\u4EF6\u7684\u5378\u8F7D\u540D\u79F0\u4E3A: ${pc5.bold(appNameClean)}`
834
+ )
835
+ );
836
+ console.log(pc5.cyan(`\u{1F449} \u4EE5\u540E\u60A8\u53EF\u4EE5\u901A\u8FC7\u8FD0\u884C\u4EE5\u4E0B\u547D\u4EE4\u6765\u5F7B\u5E95\u5378\u8F7D\u5B83\uFF1A`));
837
+ console.log(pc5.bold(pc5.yellow(` xx delete ${appNameClean}`)));
838
+ } catch (err) {
839
+ console.error(
840
+ pc5.red("\u274C AppImage \u90E8\u7F72\u5931\u8D25:"),
841
+ err instanceof Error ? err.message : err
842
+ );
843
+ }
844
+ }
845
+ async function installDeb(absPath) {
846
+ console.log(pc5.cyan(`\u{1F4E6} \u6B63\u5728\u901A\u8FC7 dpkg \u672C\u5730\u5B89\u88C5 DEB \u8F6F\u4EF6\u5305: ${absPath}...`));
847
+ const status = await spawnCommand("sudo", ["dpkg", "-i", absPath]);
848
+ if (status.success) {
849
+ console.log(pc5.green("\u2714 DEB \u8F6F\u4EF6\u5305\u90E8\u7F72\u6210\u529F\uFF01"));
850
+ try {
851
+ const { success, stdout } = await runCommand("dpkg-deb", [
852
+ "-f",
853
+ absPath,
854
+ "Package"
855
+ ]);
856
+ if (success) {
857
+ const packageName = decodeOutput(stdout).trim();
858
+ console.log(
859
+ pc5.green(
860
+ `
861
+ \u2728 \u5B89\u88C5\u6210\u529F\uFF01\u8BE5\u8F6F\u4EF6\u5305\u7684\u5B98\u65B9\u5378\u8F7D\u540D\u79F0\u4E3A: ${pc5.bold(packageName)}`
862
+ )
863
+ );
864
+ console.log(pc5.cyan(`\u{1F449} \u4EE5\u540E\u60A8\u53EF\u4EE5\u901A\u8FC7\u8FD0\u884C\u4EE5\u4E0B\u547D\u4EE4\u6765\u5F7B\u5E95\u5378\u8F7D\u5B83\uFF1A`));
865
+ console.log(pc5.bold(pc5.yellow(` xx delete ${packageName}`)));
866
+ }
867
+ } catch {
868
+ }
869
+ } else {
870
+ console.error(pc5.red(`\u274C \u5B89\u88C5\u5931\u8D25\uFF0C\u8FDB\u7A0B\u9000\u51FA\u7801: ${status.code}`));
871
+ }
872
+ }
873
+ async function installRpm(absPath) {
874
+ console.log(pc5.cyan(`\u{1F4E6} \u6B63\u5728\u901A\u8FC7 dnf \u672C\u5730\u5B89\u88C5 RPM \u8F6F\u4EF6\u5305: ${absPath}...`));
875
+ const status = await spawnCommand("sudo", ["dnf", "install", "-y", absPath]);
876
+ if (status.success) {
877
+ console.log(pc5.green("\u2714 RPM \u8F6F\u4EF6\u5305\u90E8\u7F72\u6210\u529F\uFF01"));
878
+ try {
879
+ const { success, stdout } = await runCommand("rpm", [
880
+ "-qp",
881
+ "--queryformat",
882
+ "%{NAME}",
883
+ absPath
884
+ ]);
885
+ if (success) {
886
+ const packageName = decodeOutput(stdout).trim();
887
+ console.log(
888
+ pc5.green(
889
+ `
890
+ \u2728 \u5B89\u88C5\u6210\u529F\uFF01\u8BE5\u8F6F\u4EF6\u5305\u7684\u5B98\u65B9\u5378\u8F7D\u540D\u79F0\u4E3A: ${pc5.bold(packageName)}`
891
+ )
892
+ );
893
+ console.log(pc5.cyan(`\u{1F449} \u4EE5\u540E\u60A8\u53EF\u4EE5\u901A\u8FC7\u8FD0\u884C\u4EE5\u4E0B\u547D\u4EE4\u6765\u5F7B\u5E95\u5378\u8F7D\u5B83\uFF1A`));
894
+ console.log(pc5.bold(pc5.yellow(` xx delete ${packageName}`)));
895
+ }
896
+ } catch {
897
+ }
898
+ } else {
899
+ console.error(pc5.red(`\u274C \u5B89\u88C5\u5931\u8D25\uFF0C\u8FDB\u7A0B\u9000\u51FA\u7801: ${status.code}`));
900
+ }
901
+ }
902
+ async function installTarGz(absPath) {
903
+ const home = getHomeDir();
904
+ if (!home) {
905
+ console.error(pc5.red("\u274C \u9519\u8BEF: \u65E0\u6CD5\u83B7\u53D6\u7528\u6237\u6839\u76EE\u5F55\u3002"));
906
+ return;
907
+ }
908
+ const greenAppDir = join4(home, "GreenApp");
909
+ const folderName = basename2(absPath, ".tar.gz").replace(".tar", "");
910
+ const destDir = join4(greenAppDir, folderName);
911
+ try {
912
+ await fs5.mkdir(destDir, { recursive: true });
913
+ console.log(pc5.cyan(`\u{1F4E6} \u6B63\u5728\u89E3\u538B\u7EFF\u8272\u8F6F\u4EF6\u81F3: ${destDir}...`));
914
+ const tarStatus = await spawnCommand("tar", [
915
+ "-xzf",
916
+ absPath,
917
+ "-C",
918
+ destDir
919
+ ]);
920
+ if (!tarStatus.success) {
921
+ console.error(pc5.red("\u274C \u89E3\u538B\u5931\u8D25\u3002"));
922
+ return;
923
+ }
924
+ console.log(
925
+ pc5.green("\u2714 \u89E3\u538B\u5B8C\u6210\u3002\u6B63\u5728\u626B\u63CF\u4E3B\u6267\u884C\u6587\u4EF6\u4EE5\u81EA\u52A8\u914D\u7F6E\u5FEB\u6377\u65B9\u5F0F...")
926
+ );
927
+ let exePath = "";
928
+ for (const entry of await fs5.readdir(destDir, { withFileTypes: true })) {
929
+ if (entry.isFile()) {
930
+ const fullPath = join4(destDir, entry.name);
931
+ const stat = await fs5.stat(fullPath);
932
+ const isExecutable = stat.mode ? (stat.mode & 73) !== 0 : false;
933
+ if (isExecutable && !entry.name.endsWith(".sh") && !entry.name.endsWith(".so")) {
934
+ exePath = fullPath;
935
+ break;
936
+ }
937
+ }
938
+ }
939
+ if (exePath) {
940
+ console.log(pc5.cyan(`\u{1F50D} \u53D1\u73B0\u53EF\u6267\u884C\u4E8C\u8FDB\u5236\u6587\u4EF6: ${exePath}`));
941
+ await createShortcut(exePath);
942
+ console.log(
943
+ pc5.green(
944
+ `
945
+ \u2728 \u5B89\u88C5\u6210\u529F\uFF01\u8BE5\u7EFF\u8272\u5E94\u7528\u7684\u5378\u8F7D\u540D\u79F0\u4E3A: ${pc5.bold(folderName)}`
946
+ )
947
+ );
948
+ console.log(pc5.cyan(`\u{1F449} \u4EE5\u540E\u60A8\u53EF\u4EE5\u901A\u8FC7\u8FD0\u884C\u4EE5\u4E0B\u547D\u4EE4\u6765\u5F7B\u5E95\u5378\u8F7D\u5B83\uFF1A`));
949
+ console.log(pc5.bold(pc5.yellow(` xx delete ${folderName}`)));
950
+ } else {
951
+ console.log(
952
+ pc5.yellow(
953
+ "\u26A0\uFE0F \u672A\u80FD\u5728\u89E3\u538B\u76EE\u5F55\u4E0B\u5B9A\u4F4D\u5230\u660E\u786E\u7684\u53EF\u6267\u884C\u4E8C\u8FDB\u5236\u6587\u4EF6\uFF0C\u8BF7\u540E\u7EED\u624B\u52A8\u521B\u5EFA\u3002"
954
+ )
955
+ );
956
+ }
957
+ } catch (err) {
958
+ console.error(
959
+ pc5.red("\u274C \u7EFF\u8272\u8F6F\u4EF6\u5B89\u88C5\u5931\u8D25:"),
960
+ err instanceof Error ? err.message : err
961
+ );
962
+ }
963
+ }
964
+ function registerInstallCommand(program2) {
965
+ program2.command("install [path]").description(
966
+ "\u901A\u7528\u5E94\u7528\u90E8\u7F72\u5B89\u88C5\uFF08\u81EA\u52A8\u5206\u53D1\u9002\u914D AppImage\u3001Flatpak ID\u3001tar.gz\u3001deb \u53CA rpm \u683C\u5F0F\u5305\uFF09"
967
+ ).action(async (target) => {
968
+ if (!target) {
969
+ console.error(pc5.red("\u274C \u8BF7\u63D0\u4F9B\u6709\u6548\u7684\u5B89\u88C5\u5305\u6587\u4EF6\u8DEF\u5F84\u6216 Flatpak ID\u3002"));
970
+ return;
971
+ }
972
+ const isFlatpak = !target.includes("/") && !target.includes("\\") && target.split(".").length >= 3;
973
+ if (isFlatpak) {
974
+ await createShortcut(target);
975
+ console.log(
976
+ pc5.green(
977
+ `
978
+ \u2728 \u5B89\u88C5\u6210\u529F\uFF01\u8BE5 Flatpak \u5FEB\u6377\u56FE\u6807\u7684\u5378\u8F7D\u540D\u79F0\u4E3A: ${pc5.bold(target)}`
979
+ )
980
+ );
981
+ console.log(pc5.cyan(`\u{1F449} \u4EE5\u540E\u60A8\u53EF\u4EE5\u901A\u8FC7\u8FD0\u884C\u4EE5\u4E0B\u547D\u4EE4\u6765\u5220\u9664\u8BE5\u5FEB\u6377\u56FE\u6807\uFF1A`));
982
+ console.log(pc5.bold(pc5.yellow(` xx delete ${target}`)));
983
+ return;
984
+ }
985
+ const absPath = resolve4(process.cwd(), target);
986
+ try {
987
+ await fs5.stat(absPath);
988
+ } catch {
989
+ console.error(pc5.red(`\u274C \u9519\u8BEF: \u627E\u4E0D\u5230\u6307\u5B9A\u6587\u4EF6\u6216\u5305\u8DEF\u5F84 '${target}'\u3002`));
990
+ return;
991
+ }
992
+ const lowerPath = target.toLowerCase();
993
+ if (lowerPath.endsWith(".appimage")) {
994
+ await installAppImage(absPath);
995
+ } else if (lowerPath.endsWith(".deb")) {
996
+ await installDeb(absPath);
997
+ } else if (lowerPath.endsWith(".rpm")) {
998
+ await installRpm(absPath);
999
+ } else if (lowerPath.endsWith(".tar.gz") || lowerPath.endsWith(".tgz")) {
1000
+ await installTarGz(absPath);
1001
+ } else {
1002
+ console.log(
1003
+ pc5.cyan(`\u{1F4E6} \u68C0\u6D4B\u5230\u901A\u7528\u672C\u5730\u53EF\u6267\u884C\u6587\u4EF6\uFF0C\u6B63\u5728\u76F4\u63A5\u4E3A\u5176\u914D\u7F6E\u684C\u9762\u56FE\u6807...`)
1004
+ );
1005
+ await createShortcut(absPath);
1006
+ const execName = basename2(absPath);
1007
+ console.log(
1008
+ pc5.green(`
1009
+ \u2728 \u5FEB\u6377\u65B9\u5F0F\u521B\u5EFA\u6210\u529F\uFF01\u540D\u79F0\u4E3A: ${pc5.bold(execName)}`)
1010
+ );
1011
+ }
1012
+ });
1013
+ }
1014
+
1015
+ // commands/ip.ts
1016
+ import pc6 from "picocolors";
1017
+ import os from "os";
1018
+ function getInterfaceType(name) {
1019
+ const lowerName = name.toLowerCase();
1020
+ const vpnKeywords = [
1021
+ /tun/i,
1022
+ /tap/i,
1023
+ /utun/i,
1024
+ /ppp/i,
1025
+ /tailscale/i,
1026
+ /zerotier/i,
1027
+ /wg[0-9]/i,
1028
+ /wireguard/i,
1029
+ /cisco/i,
1030
+ /forticlient/i,
1031
+ /anyconnect/i,
1032
+ /globalprotect/i
1033
+ ];
1034
+ if (vpnKeywords.some((regex) => regex.test(lowerName))) {
1035
+ return "VPN/\u5B89\u5168\u96A7\u9053";
1036
+ }
1037
+ const virtualKeywords = [
1038
+ /virtual/i,
1039
+ /vbox/i,
1040
+ /vmnet/i,
1041
+ /docker/i,
1042
+ /veth/i,
1043
+ /bridge/i,
1044
+ /gif/i,
1045
+ /stf/i,
1046
+ /wsl/i
1047
+ ];
1048
+ if (virtualKeywords.some((regex) => regex.test(lowerName))) {
1049
+ return "\u5176\u4ED6\u865A\u62DF/\u4E34\u65F6\u8BBE\u5907";
1050
+ }
1051
+ const wirelessKeywords = [/wlan/i, /wlp/i, /wi-fi/i, /无线/i, /wifi/i];
1052
+ if (wirelessKeywords.some((regex) => regex.test(lowerName))) {
1053
+ return "\u65E0\u7EBF\u7F51\u5361";
1054
+ }
1055
+ const wiredKeywords = [
1056
+ /en[0-9]/i,
1057
+ /eth[0-9]/i,
1058
+ /ethernet/i,
1059
+ /lan/i,
1060
+ /以太网/i
1061
+ ];
1062
+ if (wiredKeywords.some((regex) => regex.test(lowerName))) {
1063
+ return "\u6709\u7EBF/\u7269\u7406\u7F51\u5361";
1064
+ }
1065
+ if (lowerName.startsWith("en") || lowerName.startsWith("eth")) {
1066
+ return "\u6709\u7EBF/\u7269\u7406\u7F51\u5361";
1067
+ }
1068
+ return "\u5176\u4ED6\u865A\u62DF/\u4E34\u65F6\u8BBE\u5907";
1069
+ }
1070
+ function ipInSubnet(ip, target, netmask) {
1071
+ if (!ip || !target || !netmask) return false;
1072
+ const ipParts = ip.split(".").map(Number);
1073
+ const targetParts = target.split(".").map(Number);
1074
+ const maskParts = netmask.split(".").map(Number);
1075
+ if (ipParts.length !== 4 || targetParts.length !== 4 || maskParts.length !== 4) {
1076
+ return false;
1077
+ }
1078
+ for (let i = 0; i < 4; i++) {
1079
+ if ((ipParts[i] & maskParts[i]) !== (targetParts[i] & maskParts[i])) {
1080
+ return false;
1081
+ }
1082
+ }
1083
+ return true;
1084
+ }
1085
+ function getActiveNetworkCards() {
1086
+ const interfaces = os.networkInterfaces();
1087
+ const cardsMap = /* @__PURE__ */ new Map();
1088
+ if (!interfaces) return [];
1089
+ for (const name of Object.keys(interfaces)) {
1090
+ const lowerName = name.toLowerCase();
1091
+ if (lowerName === "lo" || lowerName.startsWith("lo") || lowerName.includes("loopback") || lowerName.includes("\u56DE\u73AF")) {
1092
+ continue;
1093
+ }
1094
+ const netList = interfaces[name];
1095
+ if (!netList) continue;
1096
+ for (const net of netList) {
1097
+ if (net.internal) continue;
1098
+ if (net.address === "127.0.0.1" || net.address === "::1" || net.address === "0.0.0.0") {
1099
+ continue;
1100
+ }
1101
+ const cardType = getInterfaceType(name);
1102
+ if (!cardsMap.has(name)) {
1103
+ cardsMap.set(name, {
1104
+ name,
1105
+ mac: net.mac || "\u672A\u77E5",
1106
+ type: cardType,
1107
+ addresses: []
1108
+ });
1109
+ }
1110
+ cardsMap.get(name).addresses.push({
1111
+ family: String(net.family),
1112
+ address: net.address,
1113
+ netmask: net.netmask || ""
1114
+ });
1115
+ }
1116
+ }
1117
+ const filteredCards = [];
1118
+ for (const card of cardsMap.values()) {
1119
+ if (card.type === "VPN/\u5B89\u5168\u96A7\u9053") {
1120
+ const hasIPv4 = card.addresses.some(
1121
+ (a) => a.family === "IPv4" || a.family === "4"
1122
+ );
1123
+ const hasGlobalIPv6 = card.addresses.some(
1124
+ (a) => (a.family === "IPv6" || a.family === "6") && !a.address.toLowerCase().startsWith("fe80:")
1125
+ );
1126
+ if (!hasIPv4 && !hasGlobalIPv6) {
1127
+ continue;
1128
+ }
1129
+ }
1130
+ filteredCards.push(card);
1131
+ }
1132
+ return filteredCards;
1133
+ }
1134
+ async function getDefaultRouteInfo() {
1135
+ const platform2 = process.platform;
1136
+ let cmd = "";
1137
+ let args = [];
1138
+ if (platform2 === "win32") {
1139
+ cmd = "powershell";
1140
+ args = [
1141
+ "-NoProfile",
1142
+ "-Command",
1143
+ "Get-NetRoute -DestinationPrefix '0.0.0.0/0' | Select-Object -Property NextHop, InterfaceAlias | ConvertTo-Json -Compress"
1144
+ ];
1145
+ } else if (platform2 === "darwin") {
1146
+ cmd = "sh";
1147
+ args = ["-c", "route -n get default"];
1148
+ } else if (platform2 === "linux") {
1149
+ cmd = "sh";
1150
+ args = ["-c", "ip route show"];
1151
+ } else {
1152
+ throw new Error("\u5F53\u524D\u7CFB\u7EDF\u6682\u4E0D\u652F\u6301\u7F51\u5173\u53CA\u9ED8\u8BA4\u8DEF\u7531\u8BBE\u5907\u68C0\u6D4B");
1153
+ }
1154
+ const { success, stdout, stderr } = await runCommand(cmd, args);
1155
+ if (!success) {
1156
+ const errorString = decodeOutput(stderr);
1157
+ throw new Error(errorString || "\u6267\u884C\u7CFB\u7EDF\u8DEF\u7531\u8868\u67E5\u8BE2\u547D\u4EE4\u5931\u8D25");
1158
+ }
1159
+ const output = decodeOutput(stdout).trim();
1160
+ if (!output) {
1161
+ throw new Error("\u7CFB\u7EDF\u8DEF\u7531\u8868\u4E2D\u672A\u68C0\u7D22\u5230\u4EFB\u4F55\u9ED8\u8BA4\u8DEF\u7531\u914D\u7F6E");
1162
+ }
1163
+ const routeInfo = { gateway: "", interfaceName: "" };
1164
+ if (platform2 === "darwin") {
1165
+ const gatewayMatch = output.match(/gateway:\s*(\S+)/i);
1166
+ const interfaceMatch = output.match(/interface:\s*(\S+)/i);
1167
+ routeInfo.gateway = gatewayMatch ? gatewayMatch[1].trim() : "";
1168
+ routeInfo.interfaceName = interfaceMatch ? interfaceMatch[1].trim() : "";
1169
+ } else if (platform2 === "linux") {
1170
+ const defaultLine = output.split("\n").find((line) => line.startsWith("default"));
1171
+ if (defaultLine) {
1172
+ const viaMatch = defaultLine.match(/via\s+(\S+)/);
1173
+ const devMatch = defaultLine.match(/dev\s+(\S+)/);
1174
+ routeInfo.gateway = viaMatch ? viaMatch[1].trim() : "";
1175
+ routeInfo.interfaceName = devMatch ? devMatch[1].trim() : "";
1176
+ }
1177
+ } else if (platform2 === "win32") {
1178
+ try {
1179
+ const parsed = JSON.parse(output);
1180
+ const activeRoute = Array.isArray(parsed) ? parsed[0] : parsed;
1181
+ routeInfo.gateway = activeRoute.NextHop ? activeRoute.NextHop.trim() : "";
1182
+ routeInfo.interfaceName = activeRoute.InterfaceAlias ? activeRoute.InterfaceAlias.trim() : "";
1183
+ } catch {
1184
+ }
1185
+ }
1186
+ return routeInfo;
1187
+ }
1188
+ function registerIpCommand(program2) {
1189
+ program2.command("ip").description("\u672C\u5730\u6D3B\u8DC3\u7F51\u5361\u3001\u672C\u673AIP\u53CA\u7F51\u5173\u4FA6\u6D4B\u5DE5\u5177").action(async () => {
1190
+ console.log(pc6.dim("\u6B63\u5728\u5206\u6790\u7F51\u7EDC\u914D\u7F6E\uFF0C\u8BF7\u7A0D\u5019...\n"));
1191
+ try {
1192
+ let defaultRoute = { gateway: "", interfaceName: "" };
1193
+ let routeError = "";
1194
+ try {
1195
+ defaultRoute = await getDefaultRouteInfo();
1196
+ } catch (err) {
1197
+ routeError = err instanceof Error ? err.message : String(err);
1198
+ }
1199
+ const cards = getActiveNetworkCards();
1200
+ if (cards.length === 0) {
1201
+ console.log(pc6.red("\u274C \u672A\u68C0\u6D4B\u5230\u4EFB\u4F55\u6D3B\u8DC3\u7684\u975E\u672C\u5730\u56DE\u73AF\u7F51\u5361\u3002"));
1202
+ return;
1203
+ }
1204
+ cards.sort((a, b) => {
1205
+ const order = {
1206
+ "\u6709\u7EBF/\u7269\u7406\u7F51\u5361": 1,
1207
+ \u65E0\u7EBF\u7F51\u5361: 2,
1208
+ "VPN/\u5B89\u5168\u96A7\u9053": 3,
1209
+ "\u5176\u4ED6\u865A\u62DF/\u4E34\u65F6\u8BBE\u5907": 4
1210
+ };
1211
+ return order[a.type] - order[b.type];
1212
+ });
1213
+ const hasUsefulCard = cards.some(
1214
+ (c) => c.type === "\u6709\u7EBF/\u7269\u7406\u7F51\u5361" || c.type === "\u65E0\u7EBF\u7F51\u5361" || c.type === "VPN/\u5B89\u5168\u96A7\u9053"
1215
+ );
1216
+ for (const card of cards) {
1217
+ if (hasUsefulCard && card.type === "\u5176\u4ED6\u865A\u62DF/\u4E34\u65F6\u8BBE\u5907") {
1218
+ continue;
1219
+ }
1220
+ const ipv4 = card.addresses.find(
1221
+ (a) => a.family === "IPv4" || a.family === "4"
1222
+ );
1223
+ const ipv6 = card.addresses.find(
1224
+ (a) => a.family === "IPv6" || a.family === "6"
1225
+ );
1226
+ const primaryAddr = ipv4 || ipv6;
1227
+ if (!primaryAddr) continue;
1228
+ let isDefaultRouteCard = false;
1229
+ if (defaultRoute.interfaceName && card.name.toLowerCase() === defaultRoute.interfaceName.toLowerCase()) {
1230
+ isDefaultRouteCard = true;
1231
+ } else if (ipv4 && defaultRoute.gateway) {
1232
+ isDefaultRouteCard = ipInSubnet(
1233
+ ipv4.address,
1234
+ defaultRoute.gateway,
1235
+ ipv4.netmask
1236
+ );
1237
+ }
1238
+ let cardGateway = pc6.dim("(\u975E\u9ED8\u8BA4\u8DEF\u7531\u51FA\u53E3\u7F51\u5361)");
1239
+ if (isDefaultRouteCard) {
1240
+ if (defaultRoute.gateway && defaultRoute.gateway !== "0.0.0.0") {
1241
+ cardGateway = pc6.yellow(defaultRoute.gateway);
1242
+ } else {
1243
+ cardGateway = pc6.yellow("\u76F4\u63A5\u70B9\u5BF9\u70B9\u96A7\u9053\u8FDE\u63A5 (Point-to-Point)");
1244
+ }
1245
+ } else if (routeError) {
1246
+ cardGateway = pc6.dim(`\u68C0\u6D4B\u5931\u8D25 (\u539F\u56E0: ${routeError})`);
1247
+ }
1248
+ console.log(
1249
+ pc6.cyan(
1250
+ `================ \u6D3B\u8DC3\u7F51\u5361\u53CA\u7F51\u5173\u4FE1\u606F [${card.type}] ================`
1251
+ )
1252
+ );
1253
+ console.log(
1254
+ `${pc6.green("\u7F51\u5361\u540D\u79F0 (Name):")} ${pc6.bold(card.name)}`
1255
+ );
1256
+ console.log(
1257
+ `${pc6.green("\u672C\u673A IP \u5730\u5740 (IP):")} ${pc6.bold(primaryAddr.address)}`
1258
+ );
1259
+ console.log(
1260
+ `${pc6.green("\u5B50\u7F51\u63A9\u7801 (Mask):")} ${primaryAddr.netmask}`
1261
+ );
1262
+ console.log(`${pc6.green("\u9ED8\u8BA4\u7F51\u5173 (Gateway):")} ${cardGateway}`);
1263
+ console.log(`${pc6.green("MAC \u5730\u5740 (MAC):")} ${card.mac}`);
1264
+ console.log(
1265
+ `${pc6.green("IP \u534F\u8BAE\u7248\u672C:")} ${primaryAddr.family === "IPv4" || primaryAddr.family === "4" ? "IPv4" : "IPv6"}`
1266
+ );
1267
+ if (ipv4 && ipv6) {
1268
+ console.log(
1269
+ `${pc6.green("\u672C\u5730 IPv6 \u5730\u5740:")} ${pc6.dim(ipv6.address)}`
1270
+ );
1271
+ }
1272
+ console.log(
1273
+ pc6.cyan("====================================================")
1274
+ );
1275
+ console.log("");
1276
+ }
1277
+ } catch (error) {
1278
+ console.error(pc6.red("\u274C \u68C0\u6D4B\u5931\u8D25\u3002"));
1279
+ if (error instanceof Error) {
1280
+ console.error(pc6.red("\u9519\u8BEF\u8BE6\u60C5:"), error.message);
1281
+ }
1282
+ }
1283
+ });
1284
+ }
1285
+
1286
+ // commands/list.ts
1287
+ import fs6 from "fs/promises";
1288
+ import pc7 from "picocolors";
1289
+ import { resolve as resolve5 } from "path";
1290
+ function registerLsCommand(program2) {
1291
+ program2.command("list [path]").description("\u5217\u51FA\u76EE\u5F55\u4E2D\u7684\u6240\u6709\u6587\u4EF6\u548C\u76EE\u5F55\uFF08\u542B\u9690\u85CF\u9879\uFF09").action(async (targetPath) => {
1292
+ const inputPath = targetPath || ".";
1293
+ const absolutePath = resolve5(process.cwd(), inputPath);
1294
+ try {
1295
+ const stat = await fs6.stat(absolutePath);
1296
+ if (!stat.isDirectory()) {
1297
+ console.error(pc7.red(`\u274C \u9519\u8BEF: '${inputPath}' \u4E0D\u662F\u4E00\u4E2A\u6709\u6548\u7684\u76EE\u5F55\u3002`));
1298
+ return;
1299
+ }
1300
+ const entries = [];
1301
+ for (const entry of await fs6.readdir(absolutePath, {
1302
+ withFileTypes: true
1303
+ })) {
1304
+ entries.push(entry);
1305
+ }
1306
+ if (entries.length === 0) {
1307
+ console.log(pc7.dim("\uFF08\u7A7A\u76EE\u5F55\uFF09"));
1308
+ return;
1309
+ }
1310
+ entries.sort((a, b) => {
1311
+ if (a.isDirectory() && !b.isDirectory()) return -1;
1312
+ if (!a.isDirectory() && b.isDirectory()) return 1;
1313
+ return a.name.localeCompare(b.name);
1314
+ });
1315
+ for (const entry of entries) {
1316
+ const isHidden = entry.name.startsWith(".");
1317
+ if (entry.isDirectory()) {
1318
+ if (isHidden) {
1319
+ console.log(pc7.dim(`\u{1F4C1} ${pc7.blue(entry.name)}/`));
1320
+ } else {
1321
+ console.log(`\u{1F4C1} ${pc7.blue(pc7.bold(entry.name))}/`);
1322
+ }
1323
+ } else {
1324
+ if (isHidden) {
1325
+ console.log(pc7.dim(`\u{1F4C4} ${entry.name}`));
1326
+ } else {
1327
+ console.log(`\u{1F4C4} ${entry.name}`);
1328
+ }
1329
+ }
1330
+ }
1331
+ } catch (err) {
1332
+ console.error(
1333
+ pc7.red(`\u274C \u65E0\u6CD5\u8BFB\u53D6\u76EE\u5F55\u5185\u5BB9:`),
1334
+ err instanceof Error ? err.message : err
1335
+ );
1336
+ }
1337
+ });
1338
+ }
1339
+
1340
+ // commands/move.ts
1341
+ import fs7 from "fs/promises";
1342
+ import pc8 from "picocolors";
1343
+ import { dirname as dirname4, resolve as resolve6, join as join5, basename as basename3 } from "path";
1344
+ async function copyRecursive2(src, dest) {
1345
+ const fileInfo = await fs7.stat(src);
1346
+ if (fileInfo.isDirectory()) {
1347
+ await fs7.mkdir(dest, { recursive: true });
1348
+ for (const entry of await fs7.readdir(src, { withFileTypes: true })) {
1349
+ await copyRecursive2(join5(src, entry.name), join5(dest, entry.name));
1350
+ }
1351
+ } else if (fileInfo.isFile()) {
1352
+ await fs7.mkdir(dirname4(dest), { recursive: true });
1353
+ await fs7.copyFile(src, dest);
1354
+ }
1355
+ }
1356
+ function registerMoveCommand(program2) {
1357
+ program2.command("move <source> <target>").description("\u79FB\u52A8\u6216\u91CD\u547D\u540D\u6587\u4EF6\u53CA\u76EE\u5F55").action(async (source, target) => {
1358
+ if (!source || !target) {
1359
+ console.error(pc8.red("\u274C \u8BF7\u63D0\u4F9B\u6E90\u8DEF\u5F84\u548C\u76EE\u6807\u8DEF\u5F84"));
1360
+ return;
1361
+ }
1362
+ const absSource = resolve6(process.cwd(), source);
1363
+ const absTarget = resolve6(process.cwd(), target);
1364
+ try {
1365
+ await fs7.stat(absSource);
1366
+ let finalTarget = absTarget;
1367
+ try {
1368
+ const targetStat = await fs7.stat(absTarget);
1369
+ if (targetStat.isDirectory()) {
1370
+ finalTarget = join5(absTarget, basename3(absSource));
1371
+ }
1372
+ } catch {
1373
+ }
1374
+ const targetParentDir = dirname4(finalTarget);
1375
+ await fs7.mkdir(targetParentDir, { recursive: true });
1376
+ console.log(pc8.cyan(`\u{1F4E6} \u6B63\u5728\u79FB\u52A8: ${source} \u27A1\uFE0F ${target}...`));
1377
+ try {
1378
+ await fs7.rename(absSource, finalTarget);
1379
+ } catch {
1380
+ await copyRecursive2(absSource, finalTarget);
1381
+ await fs7.rm(absSource, { recursive: true });
1382
+ }
1383
+ console.log(pc8.green(`\u2728 \u79FB\u52A8\u6210\u529F: ${source} \u27A1\uFE0F ${target}`));
1384
+ } catch (err) {
1385
+ if (isNotFoundError(err)) {
1386
+ console.error(pc8.red(`\u274C \u9519\u8BEF: \u6E90\u8DEF\u5F84\u4E0D\u5B58\u5728: ${absSource}`));
1387
+ } else {
1388
+ console.error(
1389
+ pc8.red("\u274C \u79FB\u52A8\u5931\u8D25:"),
1390
+ err instanceof Error ? err.message : err
1391
+ );
1392
+ }
1393
+ }
1394
+ });
1395
+ }
1396
+
1397
+ // commands/open.ts
1398
+ import fs8 from "fs/promises";
1399
+ import pc9 from "picocolors";
1400
+ import { resolve as resolve7 } from "path";
1401
+ function registerOpenCommand(program2) {
1402
+ program2.command("open [path]").description("\u5728\u7CFB\u7EDF\u6587\u4EF6\u7BA1\u7406\u5668\u4E2D\u6253\u5F00\u6307\u5B9A\u76EE\u5F55\uFF08\u9ED8\u8BA4\u5F53\u524D\u5DE5\u4F5C\u76EE\u5F55\uFF09").action(async (targetPath) => {
1403
+ const inputPath = targetPath || ".";
1404
+ const absolutePath = resolve7(process.cwd(), inputPath);
1405
+ try {
1406
+ const stat = await fs8.stat(absolutePath);
1407
+ if (!stat.isDirectory()) {
1408
+ console.error(pc9.red(`\u274C \u9519\u8BEF: '${inputPath}' \u4E0D\u662F\u4E00\u4E2A\u6709\u6548\u7684\u76EE\u5F55\u3002`));
1409
+ return;
1410
+ }
1411
+ } catch {
1412
+ console.error(pc9.red(`\u274C \u9519\u8BEF: \u627E\u4E0D\u5230\u76EE\u5F55 '${inputPath}'\u3002`));
1413
+ return;
1414
+ }
1415
+ const os3 = process.platform;
1416
+ let cmd = "";
1417
+ let args = [];
1418
+ if (os3 === "darwin") {
1419
+ cmd = "open";
1420
+ args = [absolutePath];
1421
+ } else if (os3 === "win32") {
1422
+ cmd = "explorer";
1423
+ args = [absolutePath];
1424
+ } else if (os3 === "linux") {
1425
+ cmd = "xdg-open";
1426
+ args = [absolutePath];
1427
+ } else {
1428
+ console.error(pc9.red("\u274C \u6682\u4E0D\u652F\u6301\u5728\u5F53\u524D\u7CFB\u7EDF\u4E0B\u8C03\u8D77\u6587\u4EF6\u7BA1\u7406\u5668\u3002"));
1429
+ return;
1430
+ }
1431
+ try {
1432
+ console.log(pc9.cyan(`\u{1F4C2} \u6B63\u5728\u6253\u5F00\u6587\u4EF6\u5939: ${absolutePath}...`));
1433
+ await spawnCommand(cmd, args);
1434
+ console.log(pc9.green("\u2728 \u6210\u529F\u8C03\u8D77\u6587\u4EF6\u7BA1\u7406\u5668\uFF01"));
1435
+ } catch (err) {
1436
+ console.error(
1437
+ pc9.red("\u274C \u65E0\u6CD5\u6253\u5F00\u7BA1\u7406\u5668:"),
1438
+ err instanceof Error ? err.message : err
1439
+ );
1440
+ }
1441
+ });
1442
+ }
1443
+
1444
+ // commands/park.ts
1445
+ import fs9, { open } from "fs/promises";
1446
+ import process2 from "process";
1447
+ import pc10 from "picocolors";
1448
+ import { join as join6, isAbsolute, resolve as resolve8, dirname as dirname5 } from "path";
1449
+ var CONFIG_FILE_NAME = ".park_config.json";
1450
+ function getConfigFile() {
1451
+ const home = process2.env["HOME"] || process2.env["USERPROFILE"] || process2.cwd();
1452
+ return join6(home, CONFIG_FILE_NAME);
1453
+ }
1454
+ async function readConfig() {
1455
+ try {
1456
+ const path = getConfigFile();
1457
+ const content = await fs9.readFile(path, "utf-8");
1458
+ return JSON.parse(content);
1459
+ } catch {
1460
+ return {};
1461
+ }
1462
+ }
1463
+ async function writeConfig(config) {
1464
+ try {
1465
+ const path = getConfigFile();
1466
+ await fs9.writeFile(path, JSON.stringify(config, null, 2));
1467
+ } catch (err) {
1468
+ console.error(pc10.red("\u274C \u5199\u5165\u5168\u5C40\u914D\u7F6E\u6587\u4EF6\u5931\u8D25:"), err);
1469
+ }
1470
+ }
1471
+ async function downloadImage(imageName, outputFilename, targetDir) {
1472
+ const prefix = "local.harbor.com/park-project/";
1473
+ let cleanName = imageName.trim();
1474
+ if (cleanName.startsWith(prefix)) {
1475
+ cleanName = cleanName.substring(prefix.length);
1476
+ } else if (cleanName.startsWith("local.harbor.com%2Fpark-project%2F")) {
1477
+ cleanName = decodeURIComponent(cleanName).substring(prefix.length);
1478
+ }
1479
+ const fullImageName = prefix + cleanName;
1480
+ console.log(pc10.cyan(`\u{1F4E6} \u76EE\u6807\u955C\u50CF: ${pc10.bold(fullImageName)}`));
1481
+ console.log(pc10.dim("\u6B63\u5728\u5411\u6253\u5305\u670D\u52A1\u5668\u63D0\u4EA4\u4EFB\u52A1\uFF0C\u8BF7\u7A0D\u5019...\n"));
1482
+ try {
1483
+ const response = await fetch("https://city189.cn:1091/", {
1484
+ method: "POST",
1485
+ headers: {
1486
+ accept: "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
1487
+ "accept-language": "zh-CN,zh;q=0.9",
1488
+ "cache-control": "max-age=0",
1489
+ "content-type": "application/x-www-form-urlencoded",
1490
+ "sec-ch-ua": '"Chromium";v="146", "Not-A.Brand";v="24", "Microsoft Edge";v="146"',
1491
+ "sec-ch-ua-mobile": "?0",
1492
+ "sec-ch-ua-platform": '"Windows"',
1493
+ "sec-fetch-dest": "document",
1494
+ "sec-fetch-mode": "navigate",
1495
+ "sec-fetch-site": "same-origin",
1496
+ "sec-fetch-user": "?1",
1497
+ "upgrade-insecure-requests": "1"
1498
+ },
1499
+ body: `image_names=${encodeURIComponent(fullImageName)}`,
1500
+ redirect: "manual"
1501
+ });
1502
+ let downloadUrl = "";
1503
+ let matchedFilename = "";
1504
+ const redirectUrl = response.headers.get("location");
1505
+ if (redirectUrl) {
1506
+ downloadUrl = redirectUrl.startsWith("http") ? redirectUrl.replace(/^http:/i, "https:") : `https://city189.cn:1091${redirectUrl.startsWith("/") ? "" : "/"}${redirectUrl}`;
1507
+ const filenameMatch = downloadUrl.match(/bundle_[a-f0-9]+\.tar/i);
1508
+ if (filenameMatch) {
1509
+ matchedFilename = filenameMatch[0];
1510
+ }
1511
+ } else {
1512
+ const text = await response.text();
1513
+ const match = text.match(/bundle_[a-f0-9]+\.tar/i);
1514
+ if (match) {
1515
+ matchedFilename = match[0];
1516
+ downloadUrl = `https://city189.cn:1091/download/${matchedFilename}`;
1517
+ } else {
1518
+ console.error(pc10.red("\u274C \u672A\u80FD\u5728\u670D\u52A1\u5668\u54CD\u5E94\u4E2D\u5339\u914D\u5230\u6253\u5305\u6587\u4EF6\u540D\u3002"));
1519
+ console.log(pc10.yellow("\u670D\u52A1\u5668\u539F\u59CB\u54CD\u5E94\u5982\u4E0B\uFF1A"));
1520
+ console.log(text);
1521
+ throw new Error("\u65E0\u6CD5\u63D0\u53D6\u6253\u5305\u540E\u7684\u6587\u4EF6\u540D");
1522
+ }
1523
+ }
1524
+ console.log(pc10.green(`\u2705 \u6253\u5305\u4EFB\u52A1\u63D0\u4EA4\u6210\u529F!`));
1525
+ console.log(pc10.green(`\u{1F517} \u4E0B\u8F7D\u94FE\u63A5: ${pc10.underline(downloadUrl)}`));
1526
+ console.log(pc10.cyan(`
1527
+ \u{1F4E5} \u5F00\u59CB\u4E0B\u8F7D: ${matchedFilename}...`));
1528
+ const downloadRes = await fetch(downloadUrl, {
1529
+ headers: {
1530
+ "content-type": "application/x-www-form-urlencoded",
1531
+ "sec-ch-ua": '"Chromium";v="146", "Not-A.Brand";v="24", "Microsoft Edge";v="146"',
1532
+ "sec-ch-ua-mobile": "?0",
1533
+ "sec-ch-ua-platform": '"Windows"',
1534
+ "upgrade-insecure-requests": "1"
1535
+ }
1536
+ });
1537
+ if (!downloadRes.ok) {
1538
+ throw new Error(`\u4E0B\u8F7D\u63A5\u53E3\u54CD\u5E94\u5931\u8D25\uFF0CHTTP \u72B6\u6001\u7801: ${downloadRes.status}`);
1539
+ }
1540
+ const contentLengthStr = downloadRes.headers.get("content-length");
1541
+ const totalBytes = contentLengthStr ? parseInt(contentLengthStr, 10) : 0;
1542
+ let downloadedBytes = 0;
1543
+ let downloadDir;
1544
+ if (targetDir) {
1545
+ downloadDir = resolve8(process2.cwd(), targetDir);
1546
+ } else {
1547
+ const config = await readConfig();
1548
+ downloadDir = config.defaultDownloadDir ? config.defaultDownloadDir : process2.cwd();
1549
+ }
1550
+ const baseFilename = outputFilename || matchedFilename || "bundle.tar";
1551
+ const finalPath = isAbsolute(baseFilename) ? baseFilename : join6(downloadDir, baseFilename);
1552
+ const targetDirToCreate = dirname5(finalPath);
1553
+ try {
1554
+ await fs9.mkdir(targetDirToCreate, { recursive: true });
1555
+ } catch {
1556
+ }
1557
+ const file = await open(finalPath, "w");
1558
+ if (downloadRes.body) {
1559
+ const reader = downloadRes.body.getReader();
1560
+ while (true) {
1561
+ const { done, value } = await reader.read();
1562
+ if (done) break;
1563
+ if (value) {
1564
+ await file.write(value);
1565
+ downloadedBytes += value.length;
1566
+ if (totalBytes > 0) {
1567
+ const percent = (downloadedBytes / totalBytes * 100).toFixed(2);
1568
+ const mb = (downloadedBytes / 1024 / 1024).toFixed(2);
1569
+ const totalMb = (totalBytes / 1024 / 1024).toFixed(2);
1570
+ process2.stdout.write(
1571
+ `\r\u{1F4E5} \u8FDB\u5EA6: ${percent}% (${mb} MB / ${totalMb} MB)`
1572
+ );
1573
+ } else {
1574
+ const mb = (downloadedBytes / 1024 / 1024).toFixed(2);
1575
+ process2.stdout.write(`\r\u{1F4E5} \u5DF2\u4E0B\u8F7D: ${mb} MB`);
1576
+ }
1577
+ }
1578
+ }
1579
+ }
1580
+ await file.close();
1581
+ console.log("\n" + pc10.green(`\u2728 \u4E0B\u8F7D\u5E76\u4FDD\u5B58\u6210\u529F! \u6587\u4EF6\u8DEF\u5F84: ${finalPath}`));
1582
+ } catch (error) {
1583
+ console.error(pc10.red("\n\u274C \u6267\u884C\u5931\u8D25\u3002"));
1584
+ if (error instanceof Error) {
1585
+ console.error(pc10.red("\u9519\u8BEF\u8BE6\u60C5:"), error.message);
1586
+ }
1587
+ }
1588
+ }
1589
+ function registerParkCommand(program2) {
1590
+ program2.command("park [image]").description("\u56ED\u533A\u79BB\u7EBF\u6253\u5305\u955C\u50CF\u4E0B\u8F7D\u5DE5\u5177").option(
1591
+ "-d, --dir <directory>",
1592
+ "\u6307\u5B9A\u672C\u6B21\u4E0B\u8F7D\u4FDD\u5B58\u7684\u76EE\u5F55\u8DEF\u5F84 (\u652F\u6301\u76F8\u5BF9\u8DEF\u5F84\u5982 ./ \u3001../ \u6216\u7EDD\u5BF9\u8DEF\u5F84)"
1593
+ ).option("-o, --output <filename>", "\u81EA\u5B9A\u4E49\u4FDD\u5B58\u7684\u6587\u4EF6\u540D").option("-g, --global <path>", "\u914D\u7F6E\u5168\u5C40\u9ED8\u8BA4\u4E0B\u8F7D\u76EE\u5F55").action(
1594
+ async (image, options, cmd) => {
1595
+ if (options.global) {
1596
+ const absPath = resolve8(process2.cwd(), options.global);
1597
+ await writeConfig({ defaultDownloadDir: absPath });
1598
+ console.log(pc10.green(`\u2728 \u5DF2\u6210\u529F\u8BBE\u7F6E\u5168\u5C40\u9ED8\u8BA4\u4E0B\u8F7D\u76EE\u5F55\u4E3A: ${absPath}`));
1599
+ return;
1600
+ }
1601
+ if (!image) {
1602
+ console.error(pc10.red("\u274C \u9519\u8BEF: \u672A\u6307\u5B9A\u9700\u8981\u4E0B\u8F7D\u7684\u955C\u50CF\u540D\u79F0\u3002"));
1603
+ cmd.outputHelp();
1604
+ return;
1605
+ }
1606
+ await downloadImage(image, options.output, options.dir);
1607
+ }
1608
+ );
1609
+ }
1610
+
1611
+ // commands/proxy.ts
1612
+ import pc11 from "picocolors";
1613
+ function registerProxyCommand(program2) {
1614
+ program2.command("proxy [action] [port]").description(
1615
+ "\u7BA1\u7406\u7EC8\u7AEF\u4E34\u65F6\u4EE3\u7406 (\u652F\u6301 proxy on [port] \u6216 proxy off\uFF0C\u65E0\u53C2\u6570\u65F6\u67E5\u770B\u5F53\u524D\u72B6\u6001)"
1616
+ ).action((action, port) => {
1617
+ if (action === "on") {
1618
+ const p = port || "7890";
1619
+ console.log(
1620
+ pc11.yellow(
1621
+ `\u26A0\uFE0F \u8B66\u544A: \u76F4\u63A5\u8FD0\u884C\u4E8C\u8FDB\u5236\u65E0\u6CD5\u76F4\u63A5\u4FEE\u6539\u5F53\u524D\u7EC8\u7AEF\u7684\u4E3B\u73AF\u5883\u53D8\u91CF\u3002`
1622
+ )
1623
+ );
1624
+ console.log(pc11.cyan(`\u{1F449} \u8BF7\u8FD0\u884C\u4EE5\u4E0B\u547D\u4EE4\u6765\u624B\u52A8\u542F\u7528\u4EE3\u7406\uFF1A`));
1625
+ console.log(pc11.bold(` export http_proxy="http://127.0.0.1:${p}"`));
1626
+ console.log(pc11.bold(` export https_proxy="http://127.0.0.1:${p}"`));
1627
+ console.log(pc11.bold(` export all_proxy="socks5://127.0.0.1:${p}"`));
1628
+ console.log(
1629
+ pc11.dim(
1630
+ `
1631
+ \u{1F4A1} \u63D0\u793A\uFF1A\u6267\u884C\u4E00\u6B21 'xx completion' \u5E76\u91CD\u5F00\u7EC8\u7AEF\u540E\uFF0C\u5373\u53EF\u76F4\u63A5\u8FD0\u884C 'xx proxy on' \u4E00\u952E\u5F00\u542F\uFF01`
1632
+ )
1633
+ );
1634
+ } else if (action === "off") {
1635
+ console.log(
1636
+ pc11.yellow(
1637
+ `\u26A0\uFE0F \u8B66\u544A: \u76F4\u63A5\u8FD0\u884C\u4E8C\u8FDB\u5236\u65E0\u6CD5\u76F4\u63A5\u4FEE\u6539\u5F53\u524D\u7EC8\u7AEF\u7684\u4E3B\u73AF\u5883\u53D8\u91CF\u3002`
1638
+ )
1639
+ );
1640
+ console.log(pc11.cyan(`\u{1F449} \u8BF7\u8FD0\u884C\u4EE5\u4E0B\u547D\u4EE4\u6765\u624B\u52A8\u5173\u95ED\u4EE3\u7406\uFF1A`));
1641
+ console.log(
1642
+ pc11.bold(
1643
+ ` unset http_proxy https_proxy all_proxy HTTP_PROXY HTTPS_PROXY ALL_PROXY`
1644
+ )
1645
+ );
1646
+ } else {
1647
+ const httpProxy = process.env["http_proxy"] || process.env["HTTP_PROXY"];
1648
+ const httpsProxy = process.env["https_proxy"] || process.env["HTTPS_PROXY"];
1649
+ const allProxy = process.env["all_proxy"] || process.env["ALL_PROXY"];
1650
+ if (httpProxy || httpsProxy || allProxy) {
1651
+ console.log(pc11.yellow("\u{1F50D} [xx] \u68C0\u6D4B\u5230\u5F53\u524D\u7EC8\u7AEF\u5DF2\u914D\u7F6E\u4E34\u65F6\u4EE3\u7406\uFF1A"));
1652
+ if (httpProxy) console.log(` http_proxy = ${pc11.bold(httpProxy)}`);
1653
+ if (httpsProxy) console.log(` https_proxy = ${pc11.bold(httpsProxy)}`);
1654
+ if (allProxy) console.log(` all_proxy = ${pc11.bold(allProxy)}`);
1655
+ } else {
1656
+ console.log(pc11.green("\u{1F50D} [xx] \u5F53\u524D\u7EC8\u7AEF\u672A\u914D\u7F6E\u4EFB\u4F55\u4EE3\u7406 (\u76F4\u8FDE\u6A21\u5F0F)"));
1657
+ }
1658
+ console.log(
1659
+ pc11.dim(
1660
+ "\n\u{1F4A1} \u63D0\u793A\uFF1A\u60A8\u53EF\u4EE5\u4F7F\u7528 'xx proxy on [port]' \u5F00\u542F\u6216 'xx proxy off' \u5173\u95ED\u4E34\u65F6\u4EE3\u7406\u3002"
1661
+ )
1662
+ );
1663
+ }
1664
+ });
1665
+ }
1666
+
1667
+ // commands/remove.ts
1668
+ import fs10 from "fs/promises";
1669
+ import pc12 from "picocolors";
1670
+ import { resolve as resolve9 } from "path";
1671
+ import fg from "fast-glob";
1672
+ import trash from "trash";
1673
+ function registerRemoveCommand(program2) {
1674
+ program2.command("remove <paths...>").description("\u5B89\u5168\u5730\u5C06\u6307\u5B9A\u7684\u6587\u4EF6\u6216\u76EE\u5F55\u79FB\u81F3\u7CFB\u7EDF\u56DE\u6536\u7AD9\uFF08\u652F\u6301\u901A\u914D\u7B26\u53CA\u591A\u9009\uFF09").action(async (paths) => {
1675
+ if (!paths || paths.length === 0) {
1676
+ console.error(pc12.red("\u274C \u8BF7\u63D0\u4F9B\u8981\u653E\u5165\u56DE\u6536\u7AD9\u7684\u8DEF\u5F84\u6216\u901A\u914D\u7B26\u89C4\u5219"));
1677
+ return;
1678
+ }
1679
+ const resolvedPathsToDelete = /* @__PURE__ */ new Set();
1680
+ const notFoundPaths = [];
1681
+ for (const pattern of paths) {
1682
+ const isGlob = /[*?[\]{}]/.test(pattern);
1683
+ if (isGlob) {
1684
+ try {
1685
+ const matches = await fg(pattern, {
1686
+ cwd: process.cwd(),
1687
+ absolute: true,
1688
+ onlyFiles: false,
1689
+ dot: true
1690
+ });
1691
+ for (const entry of matches) {
1692
+ resolvedPathsToDelete.add(entry);
1693
+ }
1694
+ } catch (err) {
1695
+ console.error(
1696
+ pc12.red(`\u274C \u5339\u914D\u901A\u914D\u7B26 '${pattern}' \u65F6\u53D1\u751F\u5F02\u5E38:`),
1697
+ err instanceof Error ? err.message : err
1698
+ );
1699
+ }
1700
+ } else {
1701
+ const absolutePath = resolve9(process.cwd(), pattern);
1702
+ try {
1703
+ await fs10.stat(absolutePath);
1704
+ resolvedPathsToDelete.add(absolutePath);
1705
+ } catch (err) {
1706
+ if (isNotFoundError(err)) {
1707
+ notFoundPaths.push(absolutePath);
1708
+ } else {
1709
+ console.error(
1710
+ pc12.red(`\u274C \u83B7\u53D6\u8DEF\u5F84\u72B6\u6001\u5931\u8D25 [${pattern}]:`),
1711
+ err instanceof Error ? err.message : err
1712
+ );
1713
+ }
1714
+ }
1715
+ }
1716
+ }
1717
+ if (notFoundPaths.length > 0) {
1718
+ for (const path of notFoundPaths) {
1719
+ console.error(pc12.red(`\u274C \u8DEF\u5F84\u4E0D\u5B58\u5728: ${path}`));
1720
+ }
1721
+ }
1722
+ if (resolvedPathsToDelete.size === 0) {
1723
+ console.log(pc12.yellow("\u2139\uFE0F \u672A\u80FD\u627E\u5230\u4EFB\u4F55\u4E0E\u6307\u5B9A\u6761\u4EF6\u5339\u914D\u7684\u6587\u4EF6\u6216\u76EE\u5F55\u3002"));
1724
+ return;
1725
+ }
1726
+ try {
1727
+ console.log(
1728
+ pc12.cyan(
1729
+ `\u{1F4E6} \u6B63\u5728\u5C06 ${resolvedPathsToDelete.size} \u4E2A\u9879\u79FB\u81F3\u7CFB\u7EDF\u56DE\u6536\u7AD9...`
1730
+ )
1731
+ );
1732
+ await trash(Array.from(resolvedPathsToDelete));
1733
+ for (const path of resolvedPathsToDelete) {
1734
+ console.log(pc12.dim(` - \u5DF2\u79FB\u5165\u5783\u573E\u7BB1: ${path}`));
1735
+ }
1736
+ console.log(
1737
+ pc12.green(
1738
+ `\u2728 \u6210\u529F\uFF01\u5171 ${resolvedPathsToDelete.size} \u4E2A\u6587\u4EF6/\u76EE\u5F55\u5DF2\u5B89\u5168\u9001\u81F3\u7CFB\u7EDF\u56DE\u6536\u7AD9\u3002`
1739
+ )
1740
+ );
1741
+ } catch (err) {
1742
+ console.error(
1743
+ pc12.red("\u274C \u79FB\u81F3\u56DE\u6536\u7AD9\u5931\u8D25:"),
1744
+ err instanceof Error ? err.message : err
1745
+ );
1746
+ }
1747
+ });
1748
+ }
1749
+
1750
+ // commands/search.ts
1751
+ import fs11 from "fs/promises";
1752
+ import pc13 from "picocolors";
1753
+ import { resolve as resolve10, basename as basename4, relative } from "path";
1754
+ import fg2 from "fast-glob";
1755
+ function registerSearchCommand(program2) {
1756
+ program2.command("search <keyword> [directory]").description(
1757
+ "\u9012\u5F52\u641C\u7D22\u76EE\u5F55\u4E0B\u5305\u542B\u6307\u5B9A\u5173\u952E\u8BCD\u7684\u6587\u4EF6\u6216\u76EE\u5F55\uFF08\u652F\u6301 Ctrl+\u70B9\u51FB \u5FEB\u6377\u6253\u5F00\uFF09"
1758
+ ).action(async (keyword, directory) => {
1759
+ if (!keyword) {
1760
+ console.error(pc13.red("\u274C \u8BF7\u63D0\u4F9B\u8981\u641C\u7D22\u7684\u6587\u4EF6\u540D\u5173\u952E\u8BCD"));
1761
+ return;
1762
+ }
1763
+ const startDir = directory || ".";
1764
+ const absoluteStartDir = resolve10(process.cwd(), startDir);
1765
+ try {
1766
+ const stat = await fs11.stat(absoluteStartDir);
1767
+ if (!stat.isDirectory()) {
1768
+ console.error(pc13.red(`\u274C \u9519\u8BEF: '${startDir}' \u4E0D\u662F\u4E00\u4E2A\u6709\u6548\u7684\u76EE\u5F55\u3002`));
1769
+ return;
1770
+ }
1771
+ } catch {
1772
+ console.error(pc13.red(`\u274C \u9519\u8BEF: \u627E\u4E0D\u5230\u8D77\u70B9\u76EE\u5F55 '${startDir}'\u3002`));
1773
+ return;
1774
+ }
1775
+ console.log(
1776
+ pc13.cyan(
1777
+ `\u{1F50D} \u6B63\u5728\u76EE\u5F55 ${absoluteStartDir} \u4E2D\u9012\u5F52\u641C\u5BFB\u5305\u542B "${keyword}" \u7684\u9879\u76EE...
1778
+ `
1779
+ )
1780
+ );
1781
+ let matchCount = 0;
1782
+ try {
1783
+ const entries = await fg2("**/*", {
1784
+ cwd: absoluteStartDir,
1785
+ absolute: true,
1786
+ onlyFiles: false,
1787
+ dot: true,
1788
+ ignore: [
1789
+ "**/node_modules/**",
1790
+ "**/.git/**",
1791
+ "**/dist/**",
1792
+ "**/build/**",
1793
+ "**/.cache/**"
1794
+ ]
1795
+ });
1796
+ for (const entryPath of entries) {
1797
+ const name = basename4(entryPath);
1798
+ if (name.toLowerCase().includes(keyword.toLowerCase())) {
1799
+ matchCount++;
1800
+ const relativePath = relative(absoluteStartDir, entryPath);
1801
+ const isDirectory = !name.includes(".") || entryPath.endsWith("/");
1802
+ let isDir = isDirectory;
1803
+ try {
1804
+ const entryStat = await fs11.stat(entryPath);
1805
+ isDir = entryStat.isDirectory();
1806
+ } catch {
1807
+ }
1808
+ const typeIcon = isDir ? "\u{1F4C1}" : "\u{1F4C4}";
1809
+ const fileUri = `file://${entryPath}`;
1810
+ const hyperlink = `\x1B]8;;${fileUri}\x1B\\${pc13.bold(name)}\x1B]8;;\x1B\\`;
1811
+ console.log(`${typeIcon} ${hyperlink} -> ${pc13.dim(fileUri)}`);
1812
+ }
1813
+ }
1814
+ console.log(
1815
+ pc13.green(`
1816
+ \u2728 \u641C\u7D22\u5B8C\u6210\uFF01\u5171\u627E\u5230 ${matchCount} \u4E2A\u5339\u914D\u7684\u9879\u76EE\u3002`)
1817
+ );
1818
+ } catch (err) {
1819
+ console.error(
1820
+ pc13.red("\u274C \u641C\u5BFB\u8FC7\u7A0B\u4E2D\u53D1\u751F\u9519\u8BEF:"),
1821
+ err instanceof Error ? err.message : err
1822
+ );
1823
+ }
1824
+ });
1825
+ }
1826
+
1827
+ // commands/translate.ts
1828
+ import pc14 from "picocolors";
1829
+ import { translate } from "google-translate-api-x";
1830
+ import readline from "readline";
1831
+ import process3 from "process";
1832
+ function detectTargetLanguage(text, userSpecifiedLang) {
1833
+ if (userSpecifiedLang && userSpecifiedLang !== "auto") {
1834
+ return userSpecifiedLang;
1835
+ }
1836
+ return /[a-zA-Z]/.test(text) ? "zh-CN" : "en";
1837
+ }
1838
+ async function performTranslation(text, userSpecifiedLang) {
1839
+ try {
1840
+ const targetLang = detectTargetLanguage(text, userSpecifiedLang);
1841
+ const res = await translate(text, {
1842
+ to: targetLang
1843
+ });
1844
+ console.log(
1845
+ `${pc14.green("\u8BD1\u6587:")} ${pc14.bold(res.text)} ${pc14.dim(`(${res.from.language.iso} -> ${targetLang})`)}`
1846
+ );
1847
+ } catch (err) {
1848
+ if (err instanceof Error) {
1849
+ console.error(pc14.red("\u274C \u7FFB\u8BD1\u51FA\u9519:"), err.message);
1850
+ } else {
1851
+ console.error(pc14.red("\u274C \u7FFB\u8BD1\u51FA\u9519:"), String(err));
1852
+ }
1853
+ }
1854
+ }
1855
+ function startInteractiveMode(userSpecifiedLang) {
1856
+ const rl = readline.createInterface({
1857
+ input: process3.stdin,
1858
+ output: process3.stdout,
1859
+ prompt: pc14.cyan("\u7FFB\u8BD1\u8F93\u5165 > ")
1860
+ });
1861
+ const modeTip = userSpecifiedLang === "auto" ? "\u667A\u80FD\u81EA\u52A8\u8BC6\u522B" : `\u5F3A\u5236\u76EE\u6807\u8BED\u8A00: ${userSpecifiedLang}`;
1862
+ console.log(pc14.yellow(`\u2728 \u5DF2\u8FDB\u5165\u4EA4\u4E92\u6A21\u5F0F (${modeTip})`));
1863
+ console.log(pc14.dim('\u8F93\u5165 "exit" \u6216\u6309 Ctrl+C \u9000\u51FA\n'));
1864
+ rl.prompt();
1865
+ rl.on("line", async (line) => {
1866
+ const input = line.trim();
1867
+ if (input.toLowerCase() === "exit" || input.toLowerCase() === "quit") {
1868
+ rl.close();
1869
+ return;
1870
+ }
1871
+ if (input) {
1872
+ await performTranslation(input, userSpecifiedLang);
1873
+ }
1874
+ console.log();
1875
+ rl.prompt();
1876
+ }).on("close", () => {
1877
+ console.log(pc14.blue("\n\u518D\u89C1!"));
1878
+ process3.exit(0);
1879
+ });
1880
+ }
1881
+ function registerTanslateCommand(program2) {
1882
+ program2.command("translate [text]").description("\u7EC8\u7AEF\u7FFB\u8BD1\u5DE5\u5177 (\u652F\u6301\u81EA\u52A8\u4E2D\u82F1\u4E92\u8BD1\u53CA\u4EA4\u4E92\u6A21\u5F0F)").option(
1883
+ "-t, --to <lang>",
1884
+ "\u6307\u5B9A\u76EE\u6807\u8BED\u8A00 (\u4E0D\u4F20\u5219\u6839\u636E\u8F93\u5165\u81EA\u52A8\u4E2D\u82F1\u4E92\u8BD1)",
1885
+ "auto"
1886
+ ).action(async (text, options) => {
1887
+ if (text) {
1888
+ await performTranslation(text, options.to);
1889
+ } else {
1890
+ startInteractiveMode(options.to);
1891
+ }
1892
+ });
1893
+ }
1894
+
1895
+ // commands/uninstall.ts
1896
+ import fs12 from "fs/promises";
1897
+ import pc15 from "picocolors";
1898
+ import { resolve as resolve11, join as join7 } from "path";
1899
+ function getHomeDir2() {
1900
+ return process.env["HOME"] || process.env["USERPROFILE"] || process.cwd();
1901
+ }
1902
+ async function isSnapInstalled(packageName) {
1903
+ if (!await isCommandAvailable("snap")) return false;
1904
+ try {
1905
+ const { success } = await runCommand("snap", ["list", packageName]);
1906
+ return success;
1907
+ } catch {
1908
+ return false;
1909
+ }
1910
+ }
1911
+ async function isSystemPackageInstalled(packageName) {
1912
+ try {
1913
+ const osRelease = await fs12.readFile("/etc/os-release", "utf-8");
1914
+ if (osRelease.includes("fedora") || osRelease.includes("rhel") || osRelease.includes("centos")) {
1915
+ const { success } = await runCommand("rpm", ["-q", packageName]);
1916
+ return success;
1917
+ } else {
1918
+ const { success, stdout } = await runCommand("dpkg-query", [
1919
+ "-W",
1920
+ "-f=${Status}",
1921
+ packageName
1922
+ ]);
1923
+ if (success) {
1924
+ const status = decodeOutput(stdout).trim();
1925
+ return status.includes("installed");
1926
+ }
1927
+ return false;
1928
+ }
1929
+ } catch {
1930
+ return false;
1931
+ }
1932
+ }
1933
+ async function findGreenAppPath(appName) {
1934
+ const home = getHomeDir2();
1935
+ const greenAppDir = join7(home, "GreenApp");
1936
+ const dirPath = join7(greenAppDir, appName);
1937
+ try {
1938
+ const stat = await fs12.stat(dirPath);
1939
+ if (stat.isDirectory()) return dirPath;
1940
+ } catch {
1941
+ }
1942
+ const appImagePath = join7(greenAppDir, `${appName}.AppImage`);
1943
+ const appImageLowerPath = join7(greenAppDir, `${appName}.appimage`);
1944
+ try {
1945
+ const stat = await fs12.stat(appImagePath);
1946
+ if (stat.isFile()) return appImagePath;
1947
+ } catch {
1948
+ try {
1949
+ const stat = await fs12.stat(appImageLowerPath);
1950
+ if (stat.isFile()) return appImageLowerPath;
1951
+ } catch {
1952
+ }
1953
+ }
1954
+ if (appName.toLowerCase().endsWith(".appimage")) {
1955
+ const directPath = join7(greenAppDir, appName);
1956
+ try {
1957
+ const stat = await fs12.stat(directPath);
1958
+ if (stat.isFile()) return directPath;
1959
+ } catch {
1960
+ }
1961
+ }
1962
+ return null;
1963
+ }
1964
+ async function extractDebPackageName(absPath) {
1965
+ try {
1966
+ const { success, stdout } = await runCommand("dpkg-deb", [
1967
+ "-f",
1968
+ absPath,
1969
+ "Package"
1970
+ ]);
1971
+ if (success) {
1972
+ return decodeOutput(stdout).trim();
1973
+ }
1974
+ } catch {
1975
+ }
1976
+ return void 0;
1977
+ }
1978
+ async function extractRpmPackageName(absPath) {
1979
+ try {
1980
+ const { success, stdout } = await runCommand("rpm", [
1981
+ "-qp",
1982
+ "--queryformat",
1983
+ "%{NAME}",
1984
+ absPath
1985
+ ]);
1986
+ if (success) {
1987
+ return decodeOutput(stdout).trim();
1988
+ }
1989
+ } catch {
1990
+ }
1991
+ return void 0;
1992
+ }
1993
+ async function searchGreenApps(query) {
1994
+ const home = getHomeDir2();
1995
+ const greenAppDir = join7(home, "GreenApp");
1996
+ const candidates = [];
1997
+ try {
1998
+ for (const entry of await fs12.readdir(greenAppDir, {
1999
+ withFileTypes: true
2000
+ })) {
2001
+ if (entry.name.toLowerCase().includes(query.toLowerCase())) {
2002
+ candidates.push(entry.name.replace(/\.appimage/i, ""));
2003
+ }
2004
+ }
2005
+ } catch {
2006
+ }
2007
+ return candidates;
2008
+ }
2009
+ async function searchFlatpaks(query) {
2010
+ const candidates = [];
2011
+ if (!await isCommandAvailable("flatpak")) return candidates;
2012
+ try {
2013
+ const { success, stdout } = await runCommand("flatpak", [
2014
+ "list",
2015
+ "--columns=application,name"
2016
+ ]);
2017
+ if (success) {
2018
+ const output = decodeOutput(stdout).trim();
2019
+ const lines = output.split("\n");
2020
+ for (const line of lines) {
2021
+ const parts = line.split(" ").map((p) => p.trim());
2022
+ if (parts.length >= 2) {
2023
+ const [id, name] = parts;
2024
+ if (id.toLowerCase().includes(query.toLowerCase()) || name.toLowerCase().includes(query.toLowerCase())) {
2025
+ candidates.push({ id, name });
2026
+ }
2027
+ }
2028
+ }
2029
+ }
2030
+ } catch {
2031
+ }
2032
+ return candidates;
2033
+ }
2034
+ async function searchDebPackages(query) {
2035
+ const pkgs = [];
2036
+ try {
2037
+ const { success, stdout } = await runCommand("dpkg-query", [
2038
+ "-W",
2039
+ "-f=${Package}\n",
2040
+ `*${query}*`
2041
+ ]);
2042
+ if (success) {
2043
+ const output = decodeOutput(stdout).trim();
2044
+ const lines = output.split("\n");
2045
+ for (const line of lines) {
2046
+ const name = line.trim();
2047
+ if (name && !name.startsWith("-f=")) {
2048
+ pkgs.push(name);
2049
+ }
2050
+ }
2051
+ }
2052
+ } catch {
2053
+ }
2054
+ return pkgs;
2055
+ }
2056
+ async function searchRpmPackages(query) {
2057
+ const pkgs = [];
2058
+ try {
2059
+ const { success, stdout } = await runCommand("rpm", [
2060
+ "-qa",
2061
+ "--queryformat",
2062
+ "%{NAME}\n",
2063
+ `*${query}*`
2064
+ ]);
2065
+ if (success) {
2066
+ const output = decodeOutput(stdout).trim();
2067
+ const lines = output.split("\n");
2068
+ const uniquePkgs = /* @__PURE__ */ new Set();
2069
+ for (const line of lines) {
2070
+ const name = line.trim();
2071
+ if (name) {
2072
+ uniquePkgs.add(name);
2073
+ }
2074
+ }
2075
+ pkgs.push(...uniquePkgs);
2076
+ }
2077
+ } catch {
2078
+ }
2079
+ return pkgs;
2080
+ }
2081
+ async function removeDeb(packageName) {
2082
+ console.log(pc15.cyan(`\u{1F4E6} \u6B63\u5728\u901A\u8FC7 apt \u5378\u8F7D DEB \u8F6F\u4EF6\u5305: ${packageName}...`));
2083
+ const status = await spawnCommand("sudo", [
2084
+ "apt-get",
2085
+ "remove",
2086
+ "-y",
2087
+ packageName
2088
+ ]);
2089
+ if (status.success) {
2090
+ console.log(pc15.green(`\u2714 \u8F6F\u4EF6\u5305 ${packageName} \u5DF2\u6210\u529F\u4ECE\u7CFB\u7EDF\u4E2D\u79FB\u9664\u3002`));
2091
+ } else {
2092
+ console.error(pc15.red(`\u274C \u5378\u8F7D\u5931\u8D25\uFF0C\u8FDB\u7A0B\u9000\u51FA\u7801: ${status.code}`));
2093
+ }
2094
+ }
2095
+ async function removeRpm(packageName) {
2096
+ console.log(pc15.cyan(`\u{1F4E6} \u6B63\u5728\u901A\u8FC7 dnf \u5378\u8F7D RPM \u8F6F\u4EF6\u5305: ${packageName}...`));
2097
+ const status = await spawnCommand("sudo", [
2098
+ "dnf",
2099
+ "remove",
2100
+ "-y",
2101
+ packageName
2102
+ ]);
2103
+ if (status.success) {
2104
+ console.log(pc15.green(`\u2714 \u8F6F\u4EF6\u5305 ${packageName} \u5DF2\u6210\u529F\u4ECE\u7CFB\u7EDF\u4E2D\u79FB\u9664\u3002`));
2105
+ } else {
2106
+ console.error(pc15.red(`\u274C \u5378\u8F7D\u5931\u8D25\uFF0C\u8FDB\u7A0B\u9000\u51FA\u7801: ${status.code}`));
2107
+ }
2108
+ }
2109
+ async function removeSnap(packageName) {
2110
+ console.log(pc15.cyan(`\u{1F4E6} \u6B63\u5728\u901A\u8FC7 snap \u5378\u8F7D\u8F6F\u4EF6\u5305: ${packageName}...`));
2111
+ const status = await spawnCommand("sudo", ["snap", "remove", packageName]);
2112
+ if (status.success) {
2113
+ console.log(pc15.green(`\u2714 Snap \u8F6F\u4EF6\u5305 ${packageName} \u5DF2\u6210\u529F\u4ECE\u7CFB\u7EDF\u4E2D\u79FB\u9664\u3002`));
2114
+ } else {
2115
+ console.error(pc15.red(`\u274C \u5378\u8F7D\u5931\u8D25\uFF0C\u9000\u51FA\u7801: ${status.code}`));
2116
+ }
2117
+ }
2118
+ async function uninstallFlatpak(packageName) {
2119
+ if (!await isCommandAvailable("flatpak")) {
2120
+ console.error(pc15.red("\u274C \u5F53\u524D\u7CFB\u7EDF\u4E2D\u672A\u68C0\u6D4B\u5230\u5DF2\u5B89\u88C5\u7684 flatpak \u5DE5\u5177\u3002"));
2121
+ return;
2122
+ }
2123
+ console.log(pc15.cyan(`\u{1F4E6} \u6B63\u5728\u901A\u8FC7 flatpak \u5378\u8F7D\u5E94\u7528: ${packageName}...`));
2124
+ const status = await spawnCommand("flatpak", [
2125
+ "uninstall",
2126
+ "-y",
2127
+ packageName
2128
+ ]);
2129
+ if (status.success) {
2130
+ const home = getHomeDir2();
2131
+ const desktopPath = join7(
2132
+ home,
2133
+ ".local/share/applications",
2134
+ `flatpak-${packageName}.desktop`
2135
+ );
2136
+ try {
2137
+ await fs12.rm(desktopPath);
2138
+ console.log(pc15.green(`\u2714 \u5DF2\u6E05\u9664 Flatpak \u5173\u8054\u684C\u9762\u5FEB\u6377\u56FE\u6807\u3002`));
2139
+ } catch {
2140
+ }
2141
+ console.log(pc15.green("\u2728 Flatpak \u5E94\u7528\u53CA\u56FE\u6807\u6E05\u7406\u5B8C\u6210\uFF01"));
2142
+ }
2143
+ }
2144
+ async function performRemoveGreenApp(greenPath, appName) {
2145
+ const home = getHomeDir2();
2146
+ const applicationsDir = join7(home, ".local/share/applications");
2147
+ try {
2148
+ for (const entry of await fs12.readdir(applicationsDir, {
2149
+ withFileTypes: true
2150
+ })) {
2151
+ if (entry.isFile() && entry.name.endsWith(".desktop")) {
2152
+ const filePath = join7(applicationsDir, entry.name);
2153
+ const content = await fs12.readFile(filePath, "utf-8");
2154
+ if (content.includes(greenPath) || content.includes(appName)) {
2155
+ await fs12.rm(filePath);
2156
+ console.log(pc15.green(`\u2714 \u5DF2\u6E05\u9664\u684C\u9762\u5FEB\u6377\u56FE\u6807: ${filePath}`));
2157
+ }
2158
+ }
2159
+ }
2160
+ } catch {
2161
+ }
2162
+ try {
2163
+ await fs12.rm(greenPath, { recursive: true });
2164
+ console.log(pc15.green(`\u2714 \u5DF2\u6210\u529F\u6E05\u9664\u7EFF\u8272\u8F6F\u4EF6\u4E3B\u4F53: ${greenPath}`));
2165
+ } catch (err) {
2166
+ console.error(
2167
+ pc15.red(`\u274C \u6E05\u9664\u8F6F\u4EF6\u4E3B\u4F53\u5931\u8D25:`),
2168
+ err instanceof Error ? err.message : err
2169
+ );
2170
+ }
2171
+ }
2172
+ async function performFuzzySearchAndRecommendation(query) {
2173
+ const hasSnap = await isCommandAvailable("snap");
2174
+ const [greenCands, flatpakCands, snapCands] = await Promise.all([
2175
+ searchGreenApps(query),
2176
+ searchFlatpaks(query),
2177
+ hasSnap ? (async () => {
2178
+ const candidates = [];
2179
+ try {
2180
+ const { success, stdout } = await runCommand("snap", ["list"]);
2181
+ if (success) {
2182
+ const lines = decodeOutput(stdout).split("\n");
2183
+ for (let i = 1; i < lines.length; i++) {
2184
+ const name = lines[i].trim().split(/\s+/)[0];
2185
+ if (name && name.toLowerCase().includes(query.toLowerCase())) {
2186
+ candidates.push(name);
2187
+ }
2188
+ }
2189
+ }
2190
+ } catch {
2191
+ }
2192
+ return candidates;
2193
+ })() : Promise.resolve([])
2194
+ ]);
2195
+ let systemCands = [];
2196
+ try {
2197
+ const osRelease = await fs12.readFile("/etc/os-release", "utf-8");
2198
+ if (osRelease.includes("fedora") || osRelease.includes("rhel") || osRelease.includes("centos")) {
2199
+ systemCands = await searchRpmPackages(query);
2200
+ } else {
2201
+ systemCands = await searchDebPackages(query);
2202
+ }
2203
+ } catch {
2204
+ systemCands = await searchDebPackages(query);
2205
+ }
2206
+ const totalCands = greenCands.length + flatpakCands.length + snapCands.length + systemCands.length;
2207
+ if (totalCands > 0) {
2208
+ console.log(
2209
+ pc15.cyan(
2210
+ `\u{1F4A1} \u5E2E\u60A8\u5728\u7CFB\u7EDF\u4E2D\u641C\u5BFB\u5230\u4EE5\u4E0B ${totalCands} \u4E2A\u5305\u542B "${query}" \u7684\u76F8\u5173\u5339\u914D\u9879\uFF1A
2211
+ `
2212
+ )
2213
+ );
2214
+ if (greenCands.length > 0) {
2215
+ console.log(pc15.bold(pc15.green("\u{1F4C1} [\u7EFF\u8272\u5E94\u7528] \u5019\u9009\uFF1A")));
2216
+ for (const cand of greenCands) {
2217
+ console.log(
2218
+ ` - ${cand} ${pc15.dim(`(\u5378\u8F7D\u547D\u4EE4: xx uninstall ${cand})`)}`
2219
+ );
2220
+ }
2221
+ }
2222
+ if (flatpakCands.length > 0) {
2223
+ console.log(pc15.bold(pc15.magenta("\n\u{1F4E6} [Flatpak] \u5019\u9009\uFF1A")));
2224
+ for (const cand of flatpakCands) {
2225
+ console.log(
2226
+ ` - ${cand.id} [${cand.name}] ${pc15.dim(`(\u5378\u8F7D\u547D\u4EE4: xx uninstall ${cand.id})`)}`
2227
+ );
2228
+ }
2229
+ }
2230
+ if (snapCands.length > 0) {
2231
+ console.log(pc15.bold(pc15.yellow("\n\u26A1 [Snap] \u5019\u9009\uFF1A")));
2232
+ for (const cand of snapCands) {
2233
+ console.log(
2234
+ ` - ${cand} ${pc15.dim(`(\u5378\u8F7D\u547D\u4EE4: xx uninstall ${cand})`)}`
2235
+ );
2236
+ }
2237
+ }
2238
+ if (systemCands.length > 0) {
2239
+ console.log(pc15.bold(pc15.blue("\n\u2699 [\u7CFB\u7EDF\u6E90\u7EA7] \u5019\u9009\uFF1A")));
2240
+ for (const cand of systemCands) {
2241
+ console.log(
2242
+ ` - ${cand} ${pc15.dim(`(\u5378\u8F7D\u547D\u4EE4: xx uninstall ${cand})`)}`
2243
+ );
2244
+ }
2245
+ }
2246
+ console.log(pc15.cyan(`
2247
+ \u{1F3C1} \u641C\u5BFB\u5B8C\u6210\uFF01`));
2248
+ }
2249
+ }
2250
+ async function parseUninstallTarget(target) {
2251
+ const lower = target.toLowerCase();
2252
+ const greenPath = await findGreenAppPath(target);
2253
+ if (greenPath) {
2254
+ return { type: "green", raw: target, greenPath };
2255
+ }
2256
+ const isFlatpak = !target.includes("/") && !target.includes("\\") && target.split(".").length >= 3;
2257
+ if (isFlatpak) {
2258
+ return { type: "flatpak", raw: target };
2259
+ }
2260
+ if (lower.endsWith(".deb")) {
2261
+ const absPath = resolve11(process.cwd(), target);
2262
+ try {
2263
+ const stat = await fs12.stat(absPath);
2264
+ if (stat.isFile()) {
2265
+ const extractedPackageName = await extractDebPackageName(absPath);
2266
+ return {
2267
+ type: "deb",
2268
+ raw: target,
2269
+ resolvedPath: absPath,
2270
+ extractedPackageName
2271
+ };
2272
+ }
2273
+ } catch {
2274
+ }
2275
+ }
2276
+ if (lower.endsWith(".rpm")) {
2277
+ const absPath = resolve11(process.cwd(), target);
2278
+ try {
2279
+ const stat = await fs12.stat(absPath);
2280
+ if (stat.isFile()) {
2281
+ const extractedPackageName = await extractRpmPackageName(absPath);
2282
+ return {
2283
+ type: "rpm",
2284
+ raw: target,
2285
+ resolvedPath: absPath,
2286
+ extractedPackageName
2287
+ };
2288
+ }
2289
+ } catch {
2290
+ }
2291
+ }
2292
+ if (await isSnapInstalled(target)) {
2293
+ return { type: "snap", raw: target };
2294
+ }
2295
+ if (await isSystemPackageInstalled(target)) {
2296
+ return { type: "system", raw: target };
2297
+ }
2298
+ return { type: "unknown", raw: target };
2299
+ }
2300
+ function registerUninstallCommand(program2) {
2301
+ program2.command("uninstall <package>").description("\u901A\u7528\u5E94\u7528\u5378\u8F7D\u5668\uFF08\u652F\u6301\u5305\u540D\u3001Flatpak\u3001Snap\u3001\u672C\u5730\u5305\u6216\u7EFF\u8272\u8F6F\u4EF6\uFF09").action(async (pkg) => {
2302
+ if (!pkg) {
2303
+ console.error(
2304
+ pc15.red("\u274C \u8BF7\u63D0\u4F9B\u8981\u5378\u8F7D\u7684\u8F6F\u4EF6\u5305\u540D\u79F0\u3001\u5B89\u88C5\u5305\u6216\u7EFF\u8272\u8F6F\u4EF6\u540D\u3002")
2305
+ );
2306
+ return;
2307
+ }
2308
+ try {
2309
+ const parsed = await parseUninstallTarget(pkg);
2310
+ switch (parsed.type) {
2311
+ case "green":
2312
+ await performRemoveGreenApp(parsed.greenPath, parsed.raw);
2313
+ console.log(pc15.green("\u2728 \u7EFF\u8272\u5E94\u7528\u53CA\u684C\u9762\u5FEB\u6377\u65B9\u5F0F\u6E05\u7406\u5B8C\u6210\uFF01"));
2314
+ break;
2315
+ case "flatpak":
2316
+ await uninstallFlatpak(parsed.raw);
2317
+ break;
2318
+ case "snap":
2319
+ await removeSnap(parsed.raw);
2320
+ break;
2321
+ case "deb": {
2322
+ const debPkgName = parsed.extractedPackageName || parsed.raw;
2323
+ await removeDeb(debPkgName);
2324
+ break;
2325
+ }
2326
+ case "rpm": {
2327
+ const rpmPkgName = parsed.extractedPackageName || parsed.raw;
2328
+ await removeRpm(rpmPkgName);
2329
+ break;
2330
+ }
2331
+ case "system": {
2332
+ const osRelease = await fs12.readFile("/etc/os-release", "utf-8");
2333
+ if (osRelease.includes("fedora") || osRelease.includes("rhel") || osRelease.includes("centos")) {
2334
+ await removeRpm(parsed.raw);
2335
+ } else {
2336
+ await removeDeb(parsed.raw);
2337
+ }
2338
+ break;
2339
+ }
2340
+ case "unknown":
2341
+ await performFuzzySearchAndRecommendation(parsed.raw);
2342
+ break;
2343
+ default: {
2344
+ const _exhaustiveCheck = parsed;
2345
+ throw new Error(
2346
+ `\u672A\u5904\u7406\u7684\u5378\u8F7D\u5206\u652F\u7C7B\u578B: ${JSON.stringify(_exhaustiveCheck)}`
2347
+ );
2348
+ }
2349
+ }
2350
+ } catch (err) {
2351
+ console.error(
2352
+ pc15.red("\u274C \u5378\u8F7D\u90E8\u7F72\u5931\u8D25:"),
2353
+ err instanceof Error ? err.message : String(err)
2354
+ );
2355
+ }
2356
+ });
2357
+ }
2358
+
2359
+ // commands/unzip.ts
2360
+ import fs13 from "fs/promises";
2361
+ import pc16 from "picocolors";
2362
+ import { join as join8, basename as basename6, extname, resolve as resolve12 } from "path";
2363
+
2364
+ // utils/archive.ts
2365
+ import AdmZip from "adm-zip";
2366
+ import * as tar from "tar";
2367
+ import { mkdir } from "fs/promises";
2368
+ async function compressZip(sourceDir, outputPath) {
2369
+ const zip = new AdmZip();
2370
+ zip.addLocalFolder(sourceDir);
2371
+ zip.writeZip(outputPath);
2372
+ }
2373
+ async function uncompressZip(src, destDir) {
2374
+ await mkdir(destDir, { recursive: true });
2375
+ const zip = new AdmZip(src);
2376
+ zip.extractAllTo(destDir, true);
2377
+ }
2378
+ async function uncompressTar(src, destDir) {
2379
+ await mkdir(destDir, { recursive: true });
2380
+ await tar.x({ file: src, cwd: destDir });
2381
+ }
2382
+ async function uncompressTgz(src, destDir) {
2383
+ await mkdir(destDir, { recursive: true });
2384
+ await tar.x({ file: src, gzip: true, cwd: destDir });
2385
+ }
2386
+
2387
+ // commands/unzip.ts
2388
+ async function uncompressRar(src, dest) {
2389
+ const hasUnrar = isCommandAvailable("unrar");
2390
+ if (hasUnrar) {
2391
+ console.log(pc16.cyan(`\u{1F4E6} \u6B63\u5728\u8C03\u7528\u7CFB\u7EDF unrar \u63D0\u53D6 RAR \u538B\u7F29\u5305...`));
2392
+ const status = await spawnCommand("unrar", ["x", "-y", src, dest]);
2393
+ if (!status.success) {
2394
+ throw new Error(`unrar \u6267\u884C\u5931\u8D25\uFF0C\u8FDB\u7A0B\u9000\u51FA\u7801: ${status.code}`);
2395
+ }
2396
+ return;
2397
+ }
2398
+ const hasRar = isCommandAvailable("rar");
2399
+ if (hasRar) {
2400
+ console.log(pc16.cyan(`\u{1F4E6} \u6B63\u5728\u8C03\u7528\u7CFB\u7EDF rar \u63D0\u53D6 RAR \u538B\u7F29\u5305...`));
2401
+ const status = await spawnCommand("rar", ["x", "-y", src, dest]);
2402
+ if (!status.success) {
2403
+ throw new Error(`rar \u6267\u884C\u5931\u8D25\uFF0C\u8FDB\u7A0B\u9000\u51FA\u7801: ${status.code}`);
2404
+ }
2405
+ return;
2406
+ }
2407
+ throw new Error(
2408
+ "\u60A8\u7684\u7CFB\u7EDF\u4E2D\u672A\u68C0\u6D4B\u5230 'unrar' \u6216 'rar' \u63D0\u53D6\u7A0B\u5E8F\u3002\n\u{1F449} \u63D0\u793A\uFF1A\u8BF7\u5728\u7EC8\u7AEF\u4E2D\u8FD0\u884C 'sudo dnf install unrar' \u6216 'brew install unrar' \u5B89\u88C5\u540E\u91CD\u8BD5\u3002"
2409
+ );
2410
+ }
2411
+ function registerUnzipCommand(program2) {
2412
+ program2.command("unzip [zipfile]").description(
2413
+ "\u901A\u7528\u538B\u7F29\u5305\u89E3\u538B\u5668\uFF08\u652F\u6301 .zip, .tar.gz, .tgz, .tar, .rar \u683C\u5F0F\uFF09"
2414
+ ).option("-d, --dir <directory>", "\u6307\u5B9A\u89E3\u538B\u5230\u7684\u76EE\u6807\u76EE\u5F55\u8DEF\u5F84").action(async (zipfile, options) => {
2415
+ let srcFile = zipfile;
2416
+ if (!srcFile) {
2417
+ const input = prompt(
2418
+ "\u8BF7\u8F93\u5165\u8981\u89E3\u538B\u7684\u538B\u7F29\u5305\u6587\u4EF6\u8DEF\u5F84 (Enter compressed file path):"
2419
+ );
2420
+ if (!input) {
2421
+ console.error(pc16.red("\u274C \u9519\u8BEF: \u672A\u6307\u5B9A\u6709\u6548\u7684\u538B\u7F29\u5305\u6587\u4EF6\u3002"));
2422
+ return;
2423
+ }
2424
+ srcFile = input.trim();
2425
+ }
2426
+ const absSrcFile = resolve12(srcFile);
2427
+ try {
2428
+ const stat = await fs13.stat(absSrcFile);
2429
+ if (!stat.isFile()) {
2430
+ console.error(pc16.red(`\u274C \u9519\u8BEF: '${srcFile}' \u4E0D\u662F\u4E00\u4E2A\u6709\u6548\u7684\u6587\u4EF6\u3002`));
2431
+ return;
2432
+ }
2433
+ } catch {
2434
+ console.error(pc16.red(`\u274C \u9519\u8BEF: \u627E\u4E0D\u5230\u6587\u4EF6 '${srcFile}'\u3002`));
2435
+ return;
2436
+ }
2437
+ const lowerSrc = absSrcFile.toLowerCase();
2438
+ let folderName = "";
2439
+ if (lowerSrc.endsWith(".tar.gz")) {
2440
+ folderName = basename6(absSrcFile, ".tar.gz");
2441
+ } else if (lowerSrc.endsWith(".tgz")) {
2442
+ folderName = basename6(absSrcFile, ".tgz");
2443
+ } else {
2444
+ folderName = basename6(absSrcFile, extname(absSrcFile));
2445
+ }
2446
+ let destDir = options.dir;
2447
+ if (!destDir) {
2448
+ destDir = join8(process.cwd(), folderName);
2449
+ } else {
2450
+ destDir = resolve12(process.cwd(), destDir);
2451
+ }
2452
+ try {
2453
+ console.log(pc16.cyan(`\u{1F4E6} \u6B63\u5728\u51C6\u5907\u89E3\u538B: ${absSrcFile}...`));
2454
+ console.log(pc16.cyan(`\u{1F4E5} \u76EE\u6807\u8F93\u51FA\u76EE\u5F55: ${destDir}`));
2455
+ await fs13.mkdir(destDir, { recursive: true });
2456
+ if (lowerSrc.endsWith(".tar.gz") || lowerSrc.endsWith(".tgz")) {
2457
+ await uncompressTgz(absSrcFile, destDir);
2458
+ } else if (lowerSrc.endsWith(".tar")) {
2459
+ await uncompressTar(absSrcFile, destDir);
2460
+ } else if (lowerSrc.endsWith(".zip")) {
2461
+ await uncompressZip(absSrcFile, destDir);
2462
+ } else if (lowerSrc.endsWith(".rar")) {
2463
+ await uncompressRar(absSrcFile, destDir);
2464
+ } else {
2465
+ console.log(
2466
+ pc16.yellow(
2467
+ "\u26A0\uFE0F \u672A\u80FD\u8BC6\u522B\u7684\u538B\u7F29\u5305\u683C\u5F0F\u540E\u7F00\u3002\u5C06\u9ED8\u8BA4\u5C1D\u8BD5\u4F5C\u4E3A\u6807\u51C6 ZIP \u8FDB\u884C\u63D0\u53D6..."
2468
+ )
2469
+ );
2470
+ await uncompressZip(absSrcFile, destDir);
2471
+ }
2472
+ console.log(pc16.green(`\u2728 \u63D0\u53D6\u6210\u529F\uFF01\u5DF2\u4FDD\u5B58\u5230: ${destDir}`));
2473
+ } catch (error) {
2474
+ console.error(
2475
+ pc16.red("\u274C \u63D0\u53D6\u5931\u8D25:"),
2476
+ error instanceof Error ? error.message : error
2477
+ );
2478
+ }
2479
+ });
2480
+ }
2481
+
2482
+ // commands/upgrade.ts
2483
+ import pc17 from "picocolors";
2484
+ function registerUpgradeCommand(program2) {
2485
+ program2.command("upgrade").description("\u68C0\u67E5\u5E76\u81EA\u52A8\u66F4\u65B0 xx \u547D\u4EE4\u884C\u5DE5\u5177\u81F3\u6700\u65B0\u7248\u672C").action(async () => {
2486
+ console.log(pc17.cyan("\u{1F916} \u6B63\u5728\u4E3A\u60A8\u68C0\u67E5\u5E76\u66F4\u65B0 xx \u547D\u4EE4\u884C\u5DE5\u5177..."));
2487
+ console.log(pc17.dim("\u6267\u884C\u547D\u4EE4: npm install -g @xx-in/tools@latest\n"));
2488
+ try {
2489
+ const status = await spawnCommand("npm", [
2490
+ "install",
2491
+ "-g",
2492
+ "@xx-in/tools@latest"
2493
+ ]);
2494
+ if (status.success) {
2495
+ console.log(
2496
+ pc17.cyan("\n\u{1F916} \u6B63\u5728\u4E3A\u60A8\u5F3A\u5236\u8986\u76D6\u5E76\u5237\u65B0\u7EC8\u7AEF\u81EA\u52A8\u8865\u5168\u811A\u672C...")
2497
+ );
2498
+ await autoInstallCompletion();
2499
+ console.log(
2500
+ pc17.green("\n\u2728 xx \u81EA\u52A8\u66F4\u65B0\u5E76\u91CD\u5237\u8865\u5168\u6210\u529F\uFF01\u5DF2\u6210\u529F\u52A0\u8F7D\u6700\u65B0\u7248\u672C\u3002")
2501
+ );
2502
+ } else {
2503
+ console.error(
2504
+ pc17.red(`
2505
+ \u274C \u66F4\u65B0\u5931\u8D25\uFF0C\u9000\u51FA\u4EE3\u7801 (Exit Code): ${status.code}`)
2506
+ );
2507
+ }
2508
+ } catch (err) {
2509
+ console.error(
2510
+ pc17.red(
2511
+ "\n\u274C \u65E0\u6CD5\u6267\u884C\u66F4\u65B0\u547D\u4EE4\uFF0C\u8BF7\u786E\u8BA4\u7CFB\u7EDF\u73AF\u5883\u53D8\u91CF\u4E2D\u662F\u5426\u5DF2\u6B63\u786E\u914D\u7F6E Node.js \u4E0E npm\u3002"
2512
+ )
2513
+ );
2514
+ if (err instanceof Error) {
2515
+ console.error(pc17.red("\u9519\u8BEF\u8BE6\u60C5:"), err.message);
2516
+ }
2517
+ }
2518
+ });
2519
+ }
2520
+
2521
+ // commands/zip.ts
2522
+ import fs14 from "fs/promises";
2523
+ import os2 from "os";
2524
+ import pc18 from "picocolors";
2525
+ import { join as join9, basename as basename7, relative as relative2, resolve as resolve13 } from "path";
2526
+ var IGNORE_FILE_NAME = ".cpzipignore";
2527
+ var DEFAULT_BLACKLIST = [
2528
+ "# cpzip \u5FFD\u7565\u914D\u7F6E\u6587\u4EF6",
2529
+ "# \u652F\u6301\u6587\u4EF6\u5939\u540D\u3001\u6587\u4EF6\u540D\u3001\u4EE5\u53CA\u5E26\u6709 *.ext \u540E\u7F00\u7684\u901A\u914D\u7B26",
2530
+ "node_modules",
2531
+ ".git",
2532
+ ".DS_Store",
2533
+ "dist",
2534
+ "*.zip"
2535
+ ];
2536
+ function parseIgnoreContent(content) {
2537
+ return content.split(/\r?\n/).map((line) => line.trim()).filter((line) => line && !line.startsWith("#"));
2538
+ }
2539
+ async function getBlacklist(absSrcDir) {
2540
+ const targetIgnorePath = join9(absSrcDir, IGNORE_FILE_NAME);
2541
+ const cwdIgnorePath = join9(process.cwd(), IGNORE_FILE_NAME);
2542
+ try {
2543
+ const content = await fs14.readFile(targetIgnorePath, "utf-8");
2544
+ console.log(pc18.cyan(`[zip] \u627E\u5230\u76EE\u6807\u76EE\u5F55\u4E0B\u7684\u5FFD\u7565\u6587\u4EF6: ${targetIgnorePath}`));
2545
+ return parseIgnoreContent(content);
2546
+ } catch {
2547
+ }
2548
+ try {
2549
+ const content = await fs14.readFile(cwdIgnorePath, "utf-8");
2550
+ console.log(pc18.cyan(`[zip] \u627E\u5230\u5F53\u524D\u76EE\u5F55\u4E0B\u7684\u5FFD\u7565\u6587\u4EF6: ${cwdIgnorePath}`));
2551
+ return parseIgnoreContent(content);
2552
+ } catch (err) {
2553
+ if (isNotFoundError(err)) {
2554
+ console.log(pc18.dim(`[zip] \u672A\u627E\u5230\u5FFD\u7565\u6587\u4EF6\uFF0C\u5C06\u4F7F\u7528\u5185\u7F6E\u9ED8\u8BA4\u8FC7\u6EE4\u89C4\u5219\u3002`));
2555
+ return parseIgnoreContent(DEFAULT_BLACKLIST.join("\n"));
2556
+ }
2557
+ console.error(pc18.red(`[zip] \u8BFB\u53D6\u5FFD\u7565\u6587\u4EF6\u5931\u8D25\uFF0C\u5C06\u4F7F\u7528\u5185\u7F6E\u9ED8\u8BA4\u89C4\u5219\u3002`), err);
2558
+ return parseIgnoreContent(DEFAULT_BLACKLIST.join("\n"));
2559
+ }
2560
+ }
2561
+ function isBlacklisted(pathStr, blacklist) {
2562
+ const normalized = pathStr.replace(/\\/g, "/");
2563
+ const segments = normalized.split("/");
2564
+ for (const pattern of blacklist) {
2565
+ const trimmed = pattern.trim();
2566
+ if (!trimmed) continue;
2567
+ if (segments.includes(trimmed)) {
2568
+ return true;
2569
+ }
2570
+ if (trimmed.startsWith("*.")) {
2571
+ const ext = trimmed.slice(1);
2572
+ if (normalized.endsWith(ext)) {
2573
+ return true;
2574
+ }
2575
+ }
2576
+ const patternNormalized = trimmed.replace(/\\/g, "/");
2577
+ if (normalized.endsWith(patternNormalized) || normalized.includes("/" + patternNormalized + "/")) {
2578
+ return true;
2579
+ }
2580
+ }
2581
+ return false;
2582
+ }
2583
+ async function copyRecursive3(src, dest, baseSrc, blacklist) {
2584
+ const relPath = relative2(baseSrc, src);
2585
+ if (relPath && isBlacklisted(relPath, blacklist)) {
2586
+ return;
2587
+ }
2588
+ const fileInfo = await fs14.stat(src);
2589
+ if (fileInfo.isDirectory()) {
2590
+ await fs14.mkdir(dest, { recursive: true });
2591
+ for (const entry of await fs14.readdir(src, { withFileTypes: true })) {
2592
+ const srcPath = join9(src, entry.name);
2593
+ const destPath = join9(dest, entry.name);
2594
+ await copyRecursive3(srcPath, destPath, baseSrc, blacklist);
2595
+ }
2596
+ } else if (fileInfo.isFile()) {
2597
+ await fs14.copyFile(src, dest);
2598
+ }
2599
+ }
2600
+ function registerZipCommand(program2) {
2601
+ program2.command("zip [directory]").description("\u9012\u5F52\u590D\u5236\u76EE\u5F55\u5E76\u6839\u636E\u5FFD\u7565\u89C4\u5219\u8FC7\u6EE4\u5E76\u6253\u5305\u4E3A ZIP").action(async (directory) => {
2602
+ let srcDir = directory;
2603
+ if (!srcDir) {
2604
+ const input = prompt("\u8BF7\u8F93\u5165\u8981\u6253\u5305\u7684\u76EE\u5F55\u8DEF\u5F84 (Enter directory path):");
2605
+ if (!input) {
2606
+ console.error(pc18.red("\u274C \u9519\u8BEF: \u672A\u6307\u5B9A\u6709\u6548\u7684\u8F93\u5165\u76EE\u5F55\u3002"));
2607
+ return;
2608
+ }
2609
+ srcDir = input.trim();
2610
+ }
2611
+ const absSrcDir = resolve13(srcDir);
2612
+ try {
2613
+ const stat = await fs14.stat(absSrcDir);
2614
+ if (!stat.isDirectory()) {
2615
+ console.error(pc18.red(`\u274C \u9519\u8BEF: '${srcDir}' \u4E0D\u662F\u4E00\u4E2A\u6709\u6548\u7684\u76EE\u5F55\u3002`));
2616
+ return;
2617
+ }
2618
+ } catch {
2619
+ console.error(pc18.red(`\u274C \u9519\u8BEF: \u627E\u4E0D\u5230\u76EE\u5F55 '${srcDir}'\u3002`));
2620
+ return;
2621
+ }
2622
+ const dirName = basename7(absSrcDir);
2623
+ const outputZip = join9(process.cwd(), `${dirName}.zip`);
2624
+ const blacklist = await getBlacklist(absSrcDir);
2625
+ const tempDir = await fs14.mkdtemp(join9(os2.tmpdir(), "cpzip_temp_"));
2626
+ const tempCopyTarget = join9(tempDir, dirName);
2627
+ try {
2628
+ console.log(pc18.cyan(`\u{1F4E6} \u6B63\u5728\u590D\u5236\u76EE\u5F55\u5E76\u8FC7\u6EE4\u5FFD\u7565\u9879...`));
2629
+ await copyRecursive3(absSrcDir, tempCopyTarget, absSrcDir, blacklist);
2630
+ console.log(pc18.cyan(`\u26A1 \u6B63\u5728\u6253\u5305\u4E3A ZIP \u538B\u7F29\u5305...`));
2631
+ await compressZip(tempCopyTarget, outputZip);
2632
+ console.log(pc18.green(`\u2728 \u6253\u5305\u6210\u529F\uFF01\u538B\u7F29\u5305\u4FDD\u5B58\u4E3A: ${outputZip}`));
2633
+ } catch (error) {
2634
+ console.error(pc18.red("\u274C \u6253\u5305\u5931\u8D25:"), error);
2635
+ } finally {
2636
+ try {
2637
+ await fs14.rm(tempDir, { recursive: true });
2638
+ } catch {
2639
+ }
2640
+ }
2641
+ });
2642
+ }
2643
+
2644
+ // mod.ts
2645
+ var program = new Command();
2646
+ program.name("xx").description("\u4E00\u4E2A\u5B9E\u7528\u7684\u591A\u529F\u80FD\u7CFB\u7EDF\u547D\u4EE4\u884C\u5DE5\u5177").version(package_default.version, "-V, --version", "\u663E\u793A\u7248\u672C\u53F7").helpOption("-h, --help", "\u663E\u793A\u547D\u4EE4\u5E2E\u52A9").addHelpCommand("help [command]", "\u663E\u793A\u6307\u5B9A\u547D\u4EE4\u7684\u5E2E\u52A9\u4FE1\u606F");
2647
+ registerCompletionCommand(program);
2648
+ registerCopyCommand(program);
2649
+ registerCreateCommand(program);
2650
+ registerFormatCommand(program);
2651
+ registerInstallCommand(program);
2652
+ registerIpCommand(program);
2653
+ registerLsCommand(program);
2654
+ registerMoveCommand(program);
2655
+ registerOpenCommand(program);
2656
+ registerParkCommand(program);
2657
+ registerProxyCommand(program);
2658
+ registerRemoveCommand(program);
2659
+ registerSearchCommand(program);
2660
+ registerTanslateCommand(program);
2661
+ registerUninstallCommand(program);
2662
+ registerUnzipCommand(program);
2663
+ registerUpgradeCommand(program);
2664
+ registerZipCommand(program);
2665
+ program.parse(process4.argv);
2666
+ if (process4.argv.slice(2).length === 0) {
2667
+ program.outputHelp();
2668
+ }