fnva 0.0.26 → 0.0.28

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fnva",
3
- "version": "0.0.26",
3
+ "version": "0.0.28",
4
4
  "description": "跨平台环境切换工具,支持 Java 和 LLM 环境配置",
5
5
  "author": "protagonistss",
6
6
  "license": "MIT",
package/platforms/fnva CHANGED
Binary file
Binary file
@@ -2,130 +2,81 @@
2
2
 
3
3
  const fs = require('fs');
4
4
  const path = require('path');
5
+ const { spawnSync } = require('child_process');
5
6
 
6
- /**
7
- * 确保 fnva 二进制文件有可执行权限
8
- * 这是一个全局的 postinstall 脚本,处理本地安装和全局安装的权限问题
9
- */
10
- function ensureExecutablePermissions() {
11
- try {
12
- const scriptDir = __dirname;
13
- const projectRoot = path.resolve(scriptDir, '..');
14
- const platformsDir = path.join(projectRoot, 'platforms');
15
-
16
- console.log('✅ Ensuring fnva binary permissions...');
7
+ function log(msg) {
8
+ console.log(msg);
9
+ }
17
10
 
18
- // 如果没有 platforms 目录,说明是开发模式,不需要处理
19
- if (!fs.existsSync(platformsDir)) {
20
- console.log('ℹ️ No platforms directory found, skipping permission check');
21
- return;
11
+ function ensureExecutable(filePath, label) {
12
+ try {
13
+ const stats = fs.statSync(filePath);
14
+ const hasExec = (stats.mode & 0o111) !== 0;
15
+ log(`Checking ${label}: ${filePath}`);
16
+ log(` Current permissions: ${(stats.mode & 0o777).toString(8)}`);
17
+
18
+ if (!hasExec) {
19
+ fs.chmodSync(filePath, 0o755);
20
+ const newStats = fs.statSync(filePath);
21
+ log(` Updated permissions: ${(newStats.mode & 0o777).toString(8)}`);
22
+ } else {
23
+ log(' Executable bit already set');
22
24
  }
23
25
 
24
- const platform = process.platform;
25
- const arch = process.arch === 'arm64' ? 'arm64' : 'x64';
26
- const platformDir = `${platform}-${arch}`;
27
-
28
- const binaryName = platform === 'win32' ? 'fnva.exe' : 'fnva';
29
- const archBinaryPath = path.join(platformsDir, platformDir, binaryName);
30
- const flatBinaryPath = path.join(platformsDir, binaryName);
31
-
32
- /**
33
- * 确保指定路径的二进制文件具有可执行权限,并做一次简单的运行测试
34
- */
35
- function ensureExecutable(binaryPath, label) {
36
- try {
37
- const stats = fs.statSync(binaryPath);
38
- const hasExecPermission = (stats.mode & 0o111) !== 0;
39
-
40
- console.log(`📍 Checking binary (${label}): ${binaryPath}`);
41
- console.log(` Current permissions: ${(stats.mode & 0o777).toString(8)}`);
42
-
43
- if (!hasExecPermission) {
44
- console.log('🔧 Setting executable permissions...');
45
- fs.chmodSync(binaryPath, 0o755); // rwxr-xr-x
46
-
47
- const newStats = fs.statSync(binaryPath);
48
- const newHasExecPermission = (newStats.mode & 0o111) !== 0;
49
-
50
- if (newHasExecPermission) {
51
- console.log(`✅ Successfully set executable permissions (${label})`);
52
- } else {
53
- console.log(`❌ Failed to set executable permissions (${label})`);
54
- console.log(` New permissions: ${(newStats.mode & 0o777).toString(8)}`);
55
- console.log(` Manual fix may be required: chmod +x "${binaryPath}"`);
56
- }
57
- } else {
58
- console.log(`✅ fnva binary already has executable permissions (${label})`);
59
- }
26
+ const res = spawnSync(filePath, ['--version'], { encoding: 'utf8', timeout: 3000, stdio: 'pipe' });
27
+ if (res.error && res.error.code === 'EACCES') {
28
+ log('WARNING: still not executable; please chmod +x manually');
29
+ }
30
+ } catch (err) {
31
+ log(`WARNING: could not ensure permissions for ${label}: ${err.message}`);
32
+ }
33
+ }
60
34
 
61
- // 尝试执行一次 --version 做简单验证
62
- try {
63
- const { spawnSync } = require('child_process');
64
- const testResult = spawnSync(binaryPath, ['--version'], {
65
- encoding: 'utf8',
66
- timeout: 3000,
67
- stdio: 'pipe',
68
- });
35
+ function ensureExecutablePermissions() {
36
+ const scriptDir = __dirname;
37
+ const projectRoot = path.resolve(scriptDir, '..');
38
+ const platformsDir = path.join(projectRoot, 'platforms');
69
39
 
70
- if (testResult.status === 0 || testResult.status === 1) {
71
- console.log('✅ fnva binary is executable and responding');
72
- } else if (testResult.error && testResult.error.code === 'EACCES') {
73
- console.log('❌ fnva binary still has permission issues');
74
- console.log(` Manual fix required: chmod +x "${binaryPath}"`);
75
- }
76
- } catch {
77
- // 测试失败不视为致命错误,可能是二进制本身的问题
78
- }
79
- } catch (error) {
80
- console.warn(`⚠️ Could not fix binary permissions (${label}): ${error.message}`);
81
- console.log(` Manual fix required: chmod +x "${binaryPath}"`);
82
- }
83
- }
40
+ log('Ensuring fnva binary permissions...');
84
41
 
85
- // Windows 不需要 chmod,可直接跳过
86
- if (platform === 'win32') {
87
- console.log('ℹ️ Windows platform detected, skipping permission check');
88
- } else if (fs.existsSync(archBinaryPath)) {
89
- // 优先处理新的平台子目录结构: platforms/<platform>-<arch>/fnva
90
- ensureExecutable(archBinaryPath, platformDir);
91
- } else if (fs.existsSync(flatBinaryPath)) {
92
- // 兼容旧版本扁平结构: platforms/fnva
93
- console.log('ℹ️ Platform-specific binary not found, falling back to legacy flat layout');
94
- ensureExecutable(flatBinaryPath, 'platforms/fnva');
95
- } else {
96
- console.log(`❌ Binary not found: ${archBinaryPath}`);
97
- console.log(` Also checked legacy path: ${flatBinaryPath}`);
98
- console.log(' This might indicate an incomplete installation');
99
- }
42
+ if (!fs.existsSync(platformsDir)) {
43
+ log('Info: no platforms directory found; skipping (dev install)');
44
+ return;
45
+ }
100
46
 
101
- // 额外检查:如果是全局安装,也尝试检查路径上的 fnva 权限
102
- if (process.env.npm_config_global === 'true') {
103
- try {
104
- const { execSync } = require('child_process');
105
- const globalFnvaPath = execSync('which fnva', { encoding: 'utf8' }).trim();
47
+ const platform = process.platform;
48
+ const arch = process.arch === 'arm64' ? 'arm64' : 'x64';
49
+ const platformDir = `${platform}-${arch}`;
50
+ const binaryName = platform === 'win32' ? 'fnva.exe' : 'fnva';
51
+ const archBinaryPath = path.join(platformsDir, platformDir, binaryName);
52
+ const flatBinaryPath = path.join(platformsDir, binaryName);
106
53
 
107
- if (globalFnvaPath && fs.existsSync(globalFnvaPath)) {
108
- console.log(`📍 Checking globally installed binary: ${globalFnvaPath}`);
54
+ if (platform === 'win32') {
55
+ log('Info: Windows detected; chmod not required; skipping permission changes');
56
+ return;
57
+ }
109
58
 
110
- const globalStats = fs.statSync(globalFnvaPath);
111
- const globalHasExecPermission = (globalStats.mode & 0o111) !== 0;
59
+ if (fs.existsSync(archBinaryPath)) {
60
+ ensureExecutable(archBinaryPath, platformDir);
61
+ } else if (fs.existsSync(flatBinaryPath)) {
62
+ log('Info: falling back to legacy platforms/fnva layout');
63
+ ensureExecutable(flatBinaryPath, 'platforms/fnva');
64
+ } else {
65
+ log(`Warning: binary not found: ${archBinaryPath}`);
66
+ log(` Also checked: ${flatBinaryPath}`);
67
+ }
112
68
 
113
- if (!globalHasExecPermission) {
114
- console.log('❌ Global fnva binary lacks executable permissions');
115
- console.log(` Please run: sudo chmod +x "${globalFnvaPath}"`);
116
- } else {
117
- console.log('✅ Global fnva binary has correct permissions');
118
- }
119
- }
120
- } catch {
121
- console.log('ℹ️ Could not verify global installation');
69
+ if (process.env.npm_config_global === 'true') {
70
+ try {
71
+ const which = spawnSync('which', ['fnva'], { encoding: 'utf8' });
72
+ const globalPath = which.stdout?.trim();
73
+ if (globalPath && fs.existsSync(globalPath)) {
74
+ ensureExecutable(globalPath, 'global fnva');
122
75
  }
76
+ } catch {
77
+ // ignore
123
78
  }
124
- } catch (error) {
125
- console.warn(`⚠️ Permission check failed: ${error.message}`);
126
79
  }
127
80
  }
128
81
 
129
- // 运行权限检查
130
- ensureExecutablePermissions();
131
-
82
+ ensureExecutablePermissions();
@@ -1,9 +1,12 @@
1
1
  #!/usr/bin/env node
2
2
 
3
+ // Shell integration installer for fnva (npm postinstall helper).
4
+ // Generates a lightweight function wrapper per shell that calls the real
5
+ // `fnva` binary and applies environment switch scripts.
6
+
3
7
  const fs = require('fs');
4
8
  const path = require('path');
5
9
  const os = require('os');
6
- const { spawn } = require('child_process');
7
10
 
8
11
  function detectShell() {
9
12
  if (process.platform === 'win32') {
@@ -15,7 +18,12 @@ function detectShell() {
15
18
  function getShellConfigPath(shell) {
16
19
  switch (shell) {
17
20
  case 'powershell':
18
- return path.join(process.env.USERPROFILE || os.homedir(), 'Documents', 'WindowsPowerShell', 'Microsoft.PowerShell_profile.ps1');
21
+ return path.join(
22
+ process.env.USERPROFILE || os.homedir(),
23
+ 'Documents',
24
+ 'WindowsPowerShell',
25
+ 'Microsoft.PowerShell_profile.ps1'
26
+ );
19
27
  case 'bash':
20
28
  return path.join(os.homedir(), '.bashrc');
21
29
  case 'zsh':
@@ -29,41 +37,28 @@ function getShellConfigPath(shell) {
29
37
 
30
38
  function getPowerShellFunction() {
31
39
  return `
32
- # fnva 自动化函数 - npm 安装自动添加
40
+ # fnva auto integration (added by npm install)
33
41
  function fnva {
34
42
  if ($args.Count -ge 2 -and ($args[0] -eq "java" -or $args[0] -eq "llm" -or $args[0] -eq "cc") -and ($args[1] -eq "use")) {
35
43
  $tempFile = Join-Path $env:TEMP ("fnva_script_" + (Get-Random) + ".ps1")
36
44
 
37
45
  $env:FNVAAUTOMODE = "1"
38
46
  try {
39
- # 捕获 fnva 输出并保存到临时文件
40
47
  $output = cmd.exe /c "set FNVA_AUTO_MODE=%FNVAAUTOMODE% && fnva $args" 2>&1
41
48
 
42
- # 如果输出包含 PowerShell 脚本内容,保存并执行
43
- if ($output -match '\$env:' -or $output -match 'Write-Host') {
49
+ if ($output -match '\\$env:' -or $output -match 'Write-Host') {
44
50
  $output | Out-File -FilePath $tempFile -Encoding UTF8
45
- try {
46
- & $tempFile
47
- } catch {
48
- Write-Host "执行脚本时出错: $_" -ForegroundColor Red
49
- }
51
+ try { & $tempFile } catch { Write-Host "Error executing script: $_" -ForegroundColor Red }
50
52
  } else {
51
- # 如果不是脚本内容,直接输出
52
53
  $output
53
54
  }
54
55
  } finally {
55
56
  $env:FNVAAUTOMODE = ""
56
- if (Test-Path $tempFile) {
57
- Remove-Item $tempFile -ErrorAction SilentlyContinue
58
- }
57
+ if (Test-Path $tempFile) { Remove-Item $tempFile -ErrorAction SilentlyContinue }
59
58
  }
60
59
  } else {
61
60
  $env:FNVAAUTOMODE = "1"
62
- try {
63
- cmd.exe /c "set FNVA_AUTO_MODE=%FNVAAUTOMODE% && fnva $args"
64
- } finally {
65
- $env:FNVAAUTOMODE = ""
66
- }
61
+ try { cmd.exe /c "set FNVA_AUTO_MODE=%FNVAAUTOMODE% && fnva $args" } finally { $env:FNVAAUTOMODE = "" }
67
62
  }
68
63
  }
69
64
  `;
@@ -71,17 +66,25 @@ function fnva {
71
66
 
72
67
  function getBashFunction() {
73
68
  return `
74
- # fnva 自动化函数 - npm 安装自动添加
69
+ # fnva auto integration (added by npm install)
75
70
  fnva() {
76
- if [[ \$# -ge 2 && ("\$1" == "java" || "\$1" == "llm" || "\$1" == "cc") && "\$2" == "use" ]]; then
77
- local temp_file=\$(mktemp)
78
- chmod +x "\$temp_file"
71
+ local __fnva_bin
72
+ __fnva_bin="$(command -v fnva | head -n 1)"
73
+ if [[ -z "$__fnva_bin" ]]; then
74
+ echo "fnva: binary not found in PATH" >&2
75
+ return 127
76
+ fi
77
+
78
+ if [[ $# -ge 2 && ("$1" == "java" || "$1" == "llm" || "$1" == "cc") && "$2" == "use" ]]; then
79
+ local temp_file
80
+ temp_file="$(mktemp)"
81
+ chmod +x "$temp_file"
79
82
 
80
- FNVA_AUTO_MODE=1 command fnva "\$@" > "\$temp_file"
81
- source "\$temp_file"
82
- rm -f "\$temp_file"
83
+ FNVA_AUTO_MODE=1 "$__fnva_bin" "$@" > "$temp_file"
84
+ source "$temp_file"
85
+ rm -f "$temp_file"
83
86
  else
84
- FNVA_AUTO_MODE=1 command fnva "\$@"
87
+ FNVA_AUTO_MODE=1 "$__fnva_bin" "$@"
85
88
  fi
86
89
  }
87
90
  `;
@@ -89,16 +92,22 @@ fnva() {
89
92
 
90
93
  function getFishFunction() {
91
94
  return `
92
- # fnva 自动化函数 - npm 安装自动添加
95
+ # fnva auto integration (added by npm install)
93
96
  function fnva
94
- if test (count \$argv) -ge 2; and string match -q -r "^(java|llm|cc)\$" \$argv[1]; and test \$argv[2] = "use"
97
+ set __fnva_bin (command -v fnva | head -n 1)
98
+ if test -z "$__fnva_bin"
99
+ echo "fnva: binary not found in PATH" >&2
100
+ return 127
101
+ end
102
+
103
+ if test (count $argv) -ge 2; and string match -q -r "^(java|llm|cc)$" $argv[1]; and test $argv[2] = "use"
95
104
  set temp_file (mktemp)
96
- chmod +x \$temp_file
97
- env FNVA_AUTO_MODE=1 command fnva \$argv > \$temp_file
98
- source \$temp_file
99
- rm -f \$temp_file
105
+ chmod +x $temp_file
106
+ env FNVA_AUTO_MODE=1 "$__fnva_bin" $argv > $temp_file
107
+ source $temp_file
108
+ rm -f $temp_file
100
109
  else
101
- env FNVA_AUTO_MODE=1 command fnva \$argv
110
+ env FNVA_AUTO_MODE=1 "$__fnva_bin" $argv
102
111
  end
103
112
  end
104
113
  `;
@@ -109,9 +118,8 @@ function getShellFunction(shell) {
109
118
  case 'powershell':
110
119
  return getPowerShellFunction();
111
120
  case 'bash':
112
- return getBashFunction();
113
121
  case 'zsh':
114
- return getBashFunction(); // zsh 使用和 bash 相同的语法
122
+ return getBashFunction();
115
123
  case 'fish':
116
124
  return getFishFunction();
117
125
  default:
@@ -119,13 +127,12 @@ function getShellFunction(shell) {
119
127
  }
120
128
  }
121
129
 
122
- function isFunctionInstalled(configPath, shell) {
130
+ function isFunctionInstalled(configPath) {
123
131
  if (!fs.existsSync(configPath)) {
124
132
  return false;
125
133
  }
126
-
127
134
  const content = fs.readFileSync(configPath, 'utf8');
128
- return content.includes('fnva 自动化函数 - npm 安装自动添加');
135
+ return content.includes('fnva auto integration (added by npm install)');
129
136
  }
130
137
 
131
138
  function installShellIntegration() {
@@ -133,27 +140,24 @@ function installShellIntegration() {
133
140
  const configPath = getShellConfigPath(shell);
134
141
 
135
142
  if (!configPath) {
136
- console.log(`❌ 不支持的 shell: ${shell}`);
137
- console.log('请手动配置 fnva,详见: https://github.com/your-repo/fnva');
143
+ console.log(`⚠️ Unsupported shell: ${shell}`);
144
+ console.log('Please configure fnva manually (see README).');
138
145
  return false;
139
146
  }
140
147
 
141
- if (isFunctionInstalled(configPath, shell)) {
142
- console.log(`✅ fnva shell 集成已安装在: ${configPath}`);
148
+ if (isFunctionInstalled(configPath)) {
149
+ console.log(`✅ fnva shell integration already present: ${configPath}`);
143
150
  return true;
144
151
  }
145
152
 
146
153
  try {
147
- // 确保目录存在
148
154
  const dir = path.dirname(configPath);
149
155
  if (!fs.existsSync(dir)) {
150
156
  fs.mkdirSync(dir, { recursive: true });
151
157
  }
152
158
 
153
- // 获取函数定义
154
159
  const functionCode = getShellFunction(shell);
155
160
 
156
- // 添加到配置文件
157
161
  if (fs.existsSync(configPath)) {
158
162
  const content = fs.readFileSync(configPath, 'utf8');
159
163
  fs.writeFileSync(configPath, content + '\n' + functionCode);
@@ -161,9 +165,8 @@ function installShellIntegration() {
161
165
  fs.writeFileSync(configPath, functionCode);
162
166
  }
163
167
 
164
- console.log(`✅ fnva shell 集成已安装到: ${configPath}`);
165
- console.log('🔄 请重新加载你的 shell 配置:');
166
-
168
+ console.log(`✅ fnva shell integration installed at: ${configPath}`);
169
+ console.log('🔄 Reload your shell config:');
167
170
  switch (shell) {
168
171
  case 'powershell':
169
172
  console.log(' . $PROFILE');
@@ -178,68 +181,63 @@ function installShellIntegration() {
178
181
  console.log(' source ~/.config/fish/config.fish');
179
182
  break;
180
183
  }
181
-
182
184
  return true;
183
185
  } catch (error) {
184
- console.log(`❌ 安装失败: ${error.message}`);
185
- console.log('请手动配置 fnva');
186
+ console.log(`❌ Install failed: ${error.message}`);
187
+ console.log('Please configure fnva manually (see README).');
186
188
  return false;
187
189
  }
188
190
  }
189
191
 
190
- // 询问用户是否安装
191
192
  function promptInstallation() {
192
193
  if (process.env.FNVA_SKIP_SHELL_SETUP === '1') {
193
- console.log('⏭️ 跳过 shell 集成安装');
194
+ console.log('⏭️ Skipping shell integration (FNVA_SKIP_SHELL_SETUP=1)');
194
195
  return;
195
196
  }
196
197
 
197
198
  const shell = detectShell();
198
- console.log(`🔧 检测到 shell: ${shell}`);
199
- console.log('🚀 是否安装 fnva shell 集成? (y/N)');
199
+ console.log(`🔍 Detected shell: ${shell}`);
200
+ console.log(' Install fnva shell integration? (y/N)');
200
201
 
201
- process.stdin.resume();
202
- process.stdin.setEncoding('utf8');
202
+ const readline = require('readline');
203
+ const rl = readline.createInterface({
204
+ input: process.stdin,
205
+ output: process.stdout,
206
+ });
203
207
 
204
- process.stdin.on('data', function(data) {
205
- const response = data.toString().trim().toLowerCase();
206
- if (response === 'y' || response === 'yes') {
208
+ rl.question('> ', (answer) => {
209
+ const normalized = answer.trim().toLowerCase();
210
+ if (normalized === 'y' || normalized === 'yes') {
207
211
  installShellIntegration();
208
212
  } else {
209
- console.log('⏭️ 跳过 shell 集成安装');
210
- console.log('📖 手动配置指南: https://github.com/your-repo/fnva');
213
+ console.log(' Skipped shell integration.');
211
214
  }
212
- process.exit(0);
215
+ rl.close();
213
216
  });
214
-
215
- // 10秒后自动跳过
216
- setTimeout(() => {
217
- console.log('⏭️ 超时,跳过 shell 集成安装');
218
- console.log('📖 手动配置指南: https://github.com/your-repo/fnva');
219
- process.exit(0);
220
- }, 10000);
221
217
  }
222
218
 
223
- // 主程序
224
- if (require.main === module) {
225
- console.log('🔧 fnva shell 集成安装器');
226
- console.log(`📍 Node.js 进程ID: ${process.pid}`);
227
- console.log(`📂 工作目录: ${process.cwd()}`);
228
- console.log(`🎯 参数: ${process.argv.join(' ')}`);
219
+ function main() {
220
+ console.log('🛠️ fnva shell integration installer');
221
+ console.log(`📦 Node.js version: ${process.version}`);
222
+ console.log(`📍 CWD: ${process.cwd()}`);
229
223
 
230
224
  if (process.argv.includes('--auto') || process.argv.includes('--yes')) {
231
- console.log('🚀 自动模式启动安装...');
225
+ console.log('🤖 Auto mode: installing...');
232
226
  const result = installShellIntegration();
233
- console.log(`🏁 安装结果: ${result ? '成功' : '失败'}`);
227
+ console.log(`📄 Install result: ${result ? 'success' : 'failed'}`);
234
228
  } else {
235
229
  promptInstallation();
236
230
  }
237
231
  }
238
232
 
233
+ if (require.main === module) {
234
+ main();
235
+ }
236
+
239
237
  module.exports = {
240
238
  detectShell,
241
239
  getShellConfigPath,
242
240
  getShellFunction,
243
241
  isFunctionInstalled,
244
- installShellIntegration
242
+ installShellIntegration,
245
243
  };
@@ -1,13 +1,14 @@
1
1
  #!/usr/bin/env node
2
2
 
3
+ // Shell integration uninstaller for fnva (npm postuninstall helper).
4
+ // Cleans fnva wrapper functions from common shell config files.
5
+
3
6
  const fs = require('fs');
4
7
  const path = require('path');
5
8
  const os = require('os');
6
9
 
7
10
  function detectShell() {
8
- if (process.platform === 'win32') {
9
- return 'powershell';
10
- }
11
+ if (process.platform === 'win32') return 'powershell';
11
12
  return process.env.SHELL?.split('/').pop() || 'bash';
12
13
  }
13
14
 
@@ -33,7 +34,7 @@ function cleanConfigFile(cfgPath) {
33
34
  let content = fs.readFileSync(cfgPath, 'utf8');
34
35
  const originalContent = content;
35
36
 
36
- const marker = '# fnva 自动化函数 - npm 安装自动添加';
37
+ const marker = '# fnva auto integration (added by npm install)';
37
38
  const startIndex = content.indexOf(marker);
38
39
 
39
40
  if (startIndex !== -1) {
@@ -69,10 +70,9 @@ function cleanConfigFile(cfgPath) {
69
70
  }
70
71
  }
71
72
 
72
- // 正则兜底:移除残留 fnva 片段
73
73
  if (content === originalContent) {
74
74
  content = content
75
- .replace(/# fnva 自动化函数 - npm 安装自动添加[\s\S]*?(?=\n\S|\n$)/g, '')
75
+ .replace(/# fnva auto integration \(added by npm install\)[\s\S]*?(?=\n\S|\n$)/g, '')
76
76
  .replace(/.*fnva.*\n?/g, '')
77
77
  .replace(/.*FNVAAUTOMODE.*\n?/g, '')
78
78
  .replace(/.*cmd\.exe.*fnva.*\n?/g, '')
@@ -82,50 +82,50 @@ function cleanConfigFile(cfgPath) {
82
82
 
83
83
  if (content !== originalContent) {
84
84
  fs.writeFileSync(cfgPath, content);
85
- console.log(`✅ fnva shell 集成已从 ${cfgPath} 移除`);
85
+ console.log(`✅ fnva shell integration removed from ${cfgPath}`);
86
86
  return true;
87
87
  }
88
88
 
89
- console.log(`⚠️ 未在 ${cfgPath} 找到需要清理的内容`);
89
+ console.log(`⚠️ No fnva block found in ${cfgPath}`);
90
90
  return false;
91
91
  }
92
92
 
93
93
  function removeShellIntegration(configPath, shell) {
94
- const paths = getShellConfigPaths(shell);
95
- if (configPath) paths.unshift(configPath); // 兼容传入单一路径
96
-
94
+ const paths = configPath ? [configPath] : getShellConfigPaths(shell);
97
95
  let removedAny = false;
96
+
98
97
  for (const cfgPath of paths) {
99
98
  if (!cfgPath || !fs.existsSync(cfgPath)) continue;
100
99
  try {
101
100
  const removed = cleanConfigFile(cfgPath);
102
101
  removedAny = removedAny || removed;
103
102
  } catch (error) {
104
- console.log(`❌ 移除失败 (${cfgPath}): ${error.message}`);
103
+ console.log(`❌ Remove failed (${cfgPath}): ${error.message}`);
105
104
  }
106
105
  }
107
106
 
108
107
  if (!removedAny) {
109
- console.log('⚠️ 未找到可清理的 shell 配置文件或未匹配到 fnva 片段');
108
+ console.log('⚠️ No shell config cleaned (file missing or no fnva block)');
110
109
  }
110
+
111
111
  return removedAny;
112
112
  }
113
113
 
114
114
  function main() {
115
- console.log('🧹 fnva shell 集成卸载');
115
+ console.log('🧹 fnva shell integration uninstaller');
116
116
 
117
117
  const shell = detectShell();
118
118
  const paths = getShellConfigPaths(shell);
119
119
 
120
- if (paths.length === 0) {
121
- console.log(`⚠️ 不支持的 shell: ${shell}`);
120
+ if (!paths.length) {
121
+ console.log(`⚠️ Unsupported shell: ${shell}`);
122
122
  return;
123
123
  }
124
124
 
125
125
  const success = removeShellIntegration(null, shell);
126
126
 
127
127
  if (success) {
128
- console.log('🔄 请重新加载你的 shell 配置:');
128
+ console.log('🔄 Reload your shell config:');
129
129
  switch (shell) {
130
130
  case 'powershell':
131
131
  console.log(' . $PROFILE');
@@ -151,4 +151,4 @@ module.exports = {
151
151
  detectShell,
152
152
  getShellConfigPaths,
153
153
  removeShellIntegration,
154
- };
154
+ };