fnva 0.0.42 → 0.0.43
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -1
- package/bin/fnva.js +115 -20
- package/package.json +2 -2
- package/platforms/darwin-arm64/fnva +0 -0
- package/platforms/darwin-x64/fnva +0 -0
- package/platforms/linux-arm64/fnva +0 -0
- package/platforms/linux-x64/fnva +0 -0
- package/platforms/win32-x64/fnva.exe +0 -0
- package/scripts/install-shell-integration.js +59 -30
- package/scripts/uninstall-shell-integration.js +15 -0
package/README.md
CHANGED
|
@@ -14,16 +14,18 @@ Cross-platform environment switcher for Java, Claude Code (CC), and LLM setups.
|
|
|
14
14
|
|
|
15
15
|
## Quick start
|
|
16
16
|
|
|
17
|
-
- Init shell (Bash/Zsh): `eval "$(fnva env env --shell bash)"`
|
|
17
|
+
- Init shell (Bash/Zsh): `eval "$(fnva env env --shell bash)"`
|
|
18
18
|
PowerShell: `fnva env env --shell powershell | Out-String | Invoke-Expression`
|
|
19
19
|
- Scan Java: `fnva java scan`
|
|
20
20
|
- Switch Java for current session: `eval "$(fnva java use jdk-17)"`
|
|
21
21
|
- Switch CC profile: `eval "$(fnva cc use glmcc)"`
|
|
22
|
+
- New terminals auto-restore your last active environment
|
|
22
23
|
|
|
23
24
|
## What it does
|
|
24
25
|
|
|
25
26
|
- Manages multiple Java, CC, and generic LLM configurations.
|
|
26
27
|
- Generates shell snippets to activate environments per session or by default.
|
|
28
|
+
- **Auto-restore** — new terminals automatically restore the last active CC/Java environment.
|
|
27
29
|
- Stores config at `~/.fnva/config.toml` (Windows: `%USERPROFILE%\.fnva\config.toml`).
|
|
28
30
|
- Ships as a single binary; no background daemon.
|
|
29
31
|
|
package/bin/fnva.js
CHANGED
|
@@ -44,16 +44,12 @@ function buildBinaryPath() {
|
|
|
44
44
|
return null;
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
-
// 如果设置了 FNVA_AUTO_MODE,自动使用 Node.js 模式
|
|
48
|
-
if (process.env.FNVA_AUTO_MODE === '1') {
|
|
49
|
-
return null;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
47
|
const platform = resolvePlatform();
|
|
53
48
|
const binaryCandidates = [];
|
|
54
49
|
|
|
55
50
|
// 1. Prebuilt binary shipped with the npm package
|
|
56
|
-
|
|
51
|
+
const npmBinaryPath = platformBinaryPath(platform);
|
|
52
|
+
binaryCandidates.push(npmBinaryPath);
|
|
57
53
|
|
|
58
54
|
// 2. User-provided override via environment variable
|
|
59
55
|
if (process.env.FNVA_NATIVE_PATH) {
|
|
@@ -70,12 +66,32 @@ function buildBinaryPath() {
|
|
|
70
66
|
binaryCandidates.push(path.join(targetDir, 'debug', 'fnva'));
|
|
71
67
|
}
|
|
72
68
|
|
|
69
|
+
// Debug: Show all candidates and their existence
|
|
70
|
+
if (process.env.FNVA_DEBUG === '1') {
|
|
71
|
+
console.log('[DEBUG] Looking for fnva binary...');
|
|
72
|
+
console.log('[DEBUG] Platform:', platform, 'Arch:', resolveArch());
|
|
73
|
+
console.log('[DEBUG] Binary candidates:');
|
|
74
|
+
binaryCandidates.forEach((candidate, index) => {
|
|
75
|
+
const exists = candidate && fs.existsSync(candidate);
|
|
76
|
+
console.log(` ${index + 1}. ${candidate} - ${exists ? 'EXISTS' : 'MISSING'}`);
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
|
|
73
80
|
for (const candidate of binaryCandidates) {
|
|
74
81
|
if (candidate && fs.existsSync(candidate)) {
|
|
82
|
+
if (process.env.FNVA_DEBUG === '1') {
|
|
83
|
+
console.log(`[DEBUG] Found binary at: ${candidate}`);
|
|
84
|
+
}
|
|
75
85
|
return candidate;
|
|
76
86
|
}
|
|
77
87
|
}
|
|
78
88
|
|
|
89
|
+
if (process.env.FNVA_DEBUG === '1') {
|
|
90
|
+
console.log('[DEBUG] No binary found, falling back to Node.js mode');
|
|
91
|
+
console.log('[DEBUG] Expected npm package binary path:', npmBinaryPath);
|
|
92
|
+
console.log('[DEBUG] npmBinaryPath exists:', fs.existsSync(npmBinaryPath));
|
|
93
|
+
}
|
|
94
|
+
|
|
79
95
|
return null;
|
|
80
96
|
}
|
|
81
97
|
|
|
@@ -280,15 +296,20 @@ function handleNodeOnlyMode(args) {
|
|
|
280
296
|
const path = require('path');
|
|
281
297
|
const os = require('os');
|
|
282
298
|
|
|
283
|
-
//
|
|
284
|
-
if (args.length === 0) {
|
|
285
|
-
console.log('fnva - 环境管理工具 (Node.js
|
|
299
|
+
// 只支持基本帮助信息
|
|
300
|
+
if (args.length === 0 || args[0] === '--help' || args[0] === '-h') {
|
|
301
|
+
console.log('fnva - 环境管理工具 (Node.js 降级模式)');
|
|
286
302
|
console.log('');
|
|
287
|
-
console.log('
|
|
303
|
+
console.log('⚠️ 当前运行在 Node.js 降级模式,功能有限');
|
|
304
|
+
console.log('');
|
|
305
|
+
console.log('解决方法:');
|
|
306
|
+
console.log('1. 确保 npm 包包含平台二进制文件');
|
|
307
|
+
console.log('2. 重新安装: npm install -g fnva --force');
|
|
308
|
+
console.log('3. 或者直接下载原生二进制文件');
|
|
309
|
+
console.log('');
|
|
310
|
+
console.log('临时可用功能:');
|
|
288
311
|
console.log(' java list - 列出 Java 环境');
|
|
289
312
|
console.log(' java use <n> - 切换 Java 环境');
|
|
290
|
-
console.log('');
|
|
291
|
-
console.log('注意: Node.js 模式功能有限,建议使用原生二进制版本。');
|
|
292
313
|
return;
|
|
293
314
|
}
|
|
294
315
|
|
|
@@ -368,7 +389,14 @@ function handleNodeOnlyMode(args) {
|
|
|
368
389
|
process.exit(1);
|
|
369
390
|
}
|
|
370
391
|
} else {
|
|
371
|
-
console.error(
|
|
392
|
+
console.error(`❌ Command '${args[0]}' requires native binary mode`);
|
|
393
|
+
console.error('');
|
|
394
|
+
console.error('当前运行在 Node.js 降级模式,不支持此命令');
|
|
395
|
+
console.error('');
|
|
396
|
+
console.error('解决方案:');
|
|
397
|
+
console.error('1. 重新安装 npm 包: npm install -g fnva --force');
|
|
398
|
+
console.error('2. 从 GitHub Release 下载原生二进制文件');
|
|
399
|
+
console.error('3. 或者设置 FNVA_SKIP_NATIVE=1 强制使用此模式(功能受限)');
|
|
372
400
|
process.exit(1);
|
|
373
401
|
}
|
|
374
402
|
}
|
|
@@ -377,23 +405,90 @@ function run() {
|
|
|
377
405
|
// 设置Windows控制台编码
|
|
378
406
|
EncodingUtils.setWindowsConsoleEncoding();
|
|
379
407
|
|
|
408
|
+
// 强制显示调试信息
|
|
409
|
+
const showDebug = process.env.FNVA_DEBUG === '1' || process.argv.includes('--debug');
|
|
410
|
+
|
|
411
|
+
if (showDebug) {
|
|
412
|
+
console.log('=== FNVA DEBUG INFORMATION ===');
|
|
413
|
+
console.log('Node.js version:', process.version);
|
|
414
|
+
console.log('Platform:', process.platform);
|
|
415
|
+
console.log('Architecture:', process.arch);
|
|
416
|
+
console.log('Node binary:', process.execPath);
|
|
417
|
+
console.log('Script directory:', __dirname);
|
|
418
|
+
console.log('Working directory:', process.cwd());
|
|
419
|
+
console.log('Environment variables:');
|
|
420
|
+
console.log(' FNVA_DEBUG:', process.env.FNVA_DEBUG);
|
|
421
|
+
console.log(' FNVA_SKIP_NATIVE:', process.env.FNVA_SKIP_NATIVE);
|
|
422
|
+
console.log('Command line args:', process.argv);
|
|
423
|
+
console.log('');
|
|
424
|
+
}
|
|
425
|
+
|
|
380
426
|
const binaryPath = buildBinaryPath();
|
|
381
427
|
|
|
428
|
+
if (showDebug) {
|
|
429
|
+
console.log('=== BINARY SEARCH RESULTS ===');
|
|
430
|
+
console.log('Binary path found:', binaryPath);
|
|
431
|
+
|
|
432
|
+
// 手动检查所有可能的路径
|
|
433
|
+
const fs = require('fs');
|
|
434
|
+
const path = require('path');
|
|
435
|
+
|
|
436
|
+
const scriptDir = __dirname;
|
|
437
|
+
const projectRoot = path.resolve(scriptDir, '..');
|
|
438
|
+
const platform = process.platform;
|
|
439
|
+
const arch = process.arch;
|
|
440
|
+
const platformDir = `${platform}-${arch}`;
|
|
441
|
+
const binaryName = platform === 'win32' ? 'fnva.exe' : 'fnva';
|
|
442
|
+
const expectedPath = path.join(projectRoot, 'platforms', platformDir, binaryName);
|
|
443
|
+
|
|
444
|
+
console.log('Expected binary path:', expectedPath);
|
|
445
|
+
console.log('Expected path exists:', fs.existsSync(expectedPath));
|
|
446
|
+
|
|
447
|
+
// 检查platforms目录结构
|
|
448
|
+
console.log('');
|
|
449
|
+
console.log('=== PLATFORMS DIRECTORY ===');
|
|
450
|
+
const platformsDir = path.join(projectRoot, 'platforms');
|
|
451
|
+
if (fs.existsSync(platformsDir)) {
|
|
452
|
+
const platforms = fs.readdirSync(platformsDir, { withFileTypes: true });
|
|
453
|
+
platforms.forEach(item => {
|
|
454
|
+
if (item.isDirectory()) {
|
|
455
|
+
const platformPath = path.join(platformsDir, item.name);
|
|
456
|
+
const files = fs.readdirSync(platformPath);
|
|
457
|
+
console.log(`platforms/${item.name}/:`, files);
|
|
458
|
+
}
|
|
459
|
+
});
|
|
460
|
+
} else {
|
|
461
|
+
console.log('platforms directory does not exist');
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
console.log('=== END DEBUG ===');
|
|
465
|
+
console.log('');
|
|
466
|
+
}
|
|
467
|
+
|
|
382
468
|
if (!binaryPath) {
|
|
383
|
-
if (process.env.FNVA_SKIP_NATIVE === '1'
|
|
469
|
+
if (process.env.FNVA_SKIP_NATIVE === '1') {
|
|
470
|
+
if (showDebug) {
|
|
471
|
+
console.log('Falling back to Node.js mode (FNVA_SKIP_NATIVE set)');
|
|
472
|
+
}
|
|
384
473
|
// 纯 Node.js 模式 - 实现基本的环境切换功能
|
|
385
474
|
const args = process.argv.slice(2);
|
|
386
475
|
handleNodeOnlyMode(args);
|
|
387
476
|
return;
|
|
388
477
|
}
|
|
389
478
|
|
|
390
|
-
console.error('Error: fnva native binary not found.');
|
|
479
|
+
console.error('❌ Error: fnva native binary not found.');
|
|
391
480
|
console.error('');
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
481
|
+
|
|
482
|
+
if (showDebug) {
|
|
483
|
+
console.error('🔍 Debug information is shown above');
|
|
484
|
+
console.error('');
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
console.error("💡 Solutions:");
|
|
488
|
+
console.error(" 1) Reinstall npm package: npm install -g fnva --force");
|
|
489
|
+
console.error(" 2) Download binary from GitHub Release");
|
|
490
|
+
console.error(" 3) Set FNVA_SKIP_NATIVE=1 to use Node.js mode (limited functionality)");
|
|
491
|
+
console.error(" 4) Set FNVA_DEBUG=1 to show debug information");
|
|
397
492
|
process.exit(1);
|
|
398
493
|
}
|
|
399
494
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fnva",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.43",
|
|
4
4
|
"description": "跨平台环境切换工具,支持 Java 和 LLM 环境配置",
|
|
5
5
|
"author": "protagonistss",
|
|
6
6
|
"license": "MIT",
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"build:platforms:sh": "bash scripts/build-platforms.sh",
|
|
18
18
|
"build:all": "scripts/build-all.sh",
|
|
19
19
|
"check-permissions": "node scripts/check-permissions.js",
|
|
20
|
-
"postuninstall": "
|
|
20
|
+
"postuninstall": "node scripts/uninstall-shell-integration.js"
|
|
21
21
|
},
|
|
22
22
|
"files": [
|
|
23
23
|
"bin/",
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/platforms/linux-x64/fnva
CHANGED
|
Binary file
|
|
Binary file
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// Shell integration installer for fnva (npm postinstall helper).
|
|
4
|
-
//
|
|
4
|
+
// Uses fnva's built-in template system for shell integration scripts.
|
|
5
5
|
|
|
6
6
|
const fs = require('fs');
|
|
7
7
|
const path = require('path');
|
|
8
8
|
const os = require('os');
|
|
9
|
+
const { spawnSync } = require('child_process');
|
|
9
10
|
|
|
10
11
|
// Absolute path to the packaged fnva shim (bin/fnva.js)
|
|
11
12
|
const FNVA_SHIM = path.resolve(__dirname, '..', 'bin', 'fnva.js');
|
|
@@ -37,52 +38,70 @@ function getShellConfigPath(shell) {
|
|
|
37
38
|
}
|
|
38
39
|
}
|
|
39
40
|
|
|
41
|
+
// Get integration script from fnva command (uses Rust templates)
|
|
42
|
+
function getIntegrationScript(shell) {
|
|
43
|
+
try {
|
|
44
|
+
const result = spawnSync('node', [FNVA_SHIM, 'env', 'shell-integration', '-s', shell], {
|
|
45
|
+
encoding: 'utf8',
|
|
46
|
+
cwd: path.resolve(__dirname, '..')
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
if (result.status === 0 && result.stdout) {
|
|
50
|
+
return result.stdout;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
console.log(`Warning: Failed to get integration script from fnva (exit code: ${result.status})`);
|
|
54
|
+
if (result.stderr) {
|
|
55
|
+
console.log(`stderr: ${result.stderr}`);
|
|
56
|
+
}
|
|
57
|
+
return '';
|
|
58
|
+
} catch (error) {
|
|
59
|
+
console.log(`Warning: Failed to call fnva for integration script: ${error.message}`);
|
|
60
|
+
return '';
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
40
64
|
function getPowerShellFunction() {
|
|
65
|
+
// Get integration script from Rust template
|
|
66
|
+
const integrationScript = getIntegrationScript('powershell');
|
|
67
|
+
|
|
41
68
|
return `
|
|
69
|
+
${integrationScript}
|
|
70
|
+
|
|
42
71
|
# fnva auto integration (added by npm install)
|
|
43
72
|
function fnva {
|
|
44
73
|
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")) {
|
|
45
74
|
$tempFile = Join-Path $env:TEMP ("fnva_script_" + (Get-Random) + ".ps1")
|
|
46
75
|
|
|
47
|
-
$env:FNVAAUTOMODE = "1"
|
|
48
76
|
try {
|
|
49
|
-
|
|
77
|
+
# Directly pipe output to temp file to avoid encoding issues
|
|
78
|
+
& fnva.cmd @args 2>&1 | Out-File -FilePath $tempFile -Encoding UTF8
|
|
50
79
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
80
|
+
# Check if file contains environment variables
|
|
81
|
+
$content = Get-Content $tempFile -Raw -Encoding UTF8
|
|
82
|
+
if ($content -match '\\$env:' -or $content -match 'Write-Host') {
|
|
83
|
+
# Use dot sourcing to execute in current scope
|
|
84
|
+
. $tempFile
|
|
54
85
|
} else {
|
|
55
|
-
$
|
|
86
|
+
$content
|
|
56
87
|
}
|
|
57
88
|
} finally {
|
|
58
|
-
$env:FNVAAUTOMODE = ""
|
|
59
89
|
if (Test-Path $tempFile) { Remove-Item $tempFile -ErrorAction SilentlyContinue }
|
|
60
90
|
}
|
|
61
91
|
} else {
|
|
62
|
-
|
|
63
|
-
try { cmd.exe /c "set FNVA_AUTO_MODE=%FNVAAUTOMODE% && fnva $args" } finally { $env:FNVAAUTOMODE = "" }
|
|
92
|
+
& fnva.cmd @args
|
|
64
93
|
}
|
|
65
94
|
}
|
|
66
95
|
`;
|
|
67
96
|
}
|
|
68
97
|
|
|
69
|
-
function resolveBinaryPath() {
|
|
70
|
-
// Prefer real binary, avoid this function name
|
|
71
|
-
if (process.platform === 'win32') {
|
|
72
|
-
return process.argv[0];
|
|
73
|
-
}
|
|
74
|
-
let bin = '';
|
|
75
|
-
try {
|
|
76
|
-
const which = require('child_process').spawnSync('which', ['fnva'], { encoding: 'utf8' });
|
|
77
|
-
if (which.status === 0) {
|
|
78
|
-
bin = (which.stdout || '').trim();
|
|
79
|
-
}
|
|
80
|
-
} catch {}
|
|
81
|
-
return bin;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
98
|
function getBashFunction() {
|
|
99
|
+
// Get integration script from Rust template
|
|
100
|
+
const integrationScript = getIntegrationScript('bash');
|
|
101
|
+
|
|
85
102
|
return `
|
|
103
|
+
${integrationScript}
|
|
104
|
+
|
|
86
105
|
# fnva auto integration (added by npm install)
|
|
87
106
|
fnva() {
|
|
88
107
|
local __fnva_bin="${FNVA_SHIM}"
|
|
@@ -96,18 +115,23 @@ fnva() {
|
|
|
96
115
|
temp_file="$(mktemp)"
|
|
97
116
|
chmod +x "$temp_file"
|
|
98
117
|
|
|
99
|
-
|
|
118
|
+
"$__fnva_bin" "$@" > "$temp_file"
|
|
100
119
|
source "$temp_file"
|
|
101
120
|
rm -f "$temp_file"
|
|
102
121
|
else
|
|
103
|
-
|
|
122
|
+
"$__fnva_bin" "$@"
|
|
104
123
|
fi
|
|
105
124
|
}
|
|
106
125
|
`;
|
|
107
126
|
}
|
|
108
127
|
|
|
109
128
|
function getFishFunction() {
|
|
129
|
+
// Get integration script from Rust template
|
|
130
|
+
const integrationScript = getIntegrationScript('fish');
|
|
131
|
+
|
|
110
132
|
return `
|
|
133
|
+
${integrationScript}
|
|
134
|
+
|
|
111
135
|
# fnva auto integration (added by npm install)
|
|
112
136
|
function fnva
|
|
113
137
|
set __fnva_bin "${FNVA_SHIM}"
|
|
@@ -119,11 +143,11 @@ function fnva
|
|
|
119
143
|
if test (count $argv) -ge 2; and string match -q -r "^(java|llm|cc)$" $argv[1]; and test $argv[2] = "use"
|
|
120
144
|
set temp_file (mktemp)
|
|
121
145
|
chmod +x $temp_file
|
|
122
|
-
env
|
|
146
|
+
env "$__fnva_bin" $argv > $temp_file
|
|
123
147
|
source $temp_file
|
|
124
148
|
rm -f $temp_file
|
|
125
149
|
else
|
|
126
|
-
env
|
|
150
|
+
env "$__fnva_bin" $argv
|
|
127
151
|
end
|
|
128
152
|
end
|
|
129
153
|
`;
|
|
@@ -135,7 +159,7 @@ function getShellFunction(shell) {
|
|
|
135
159
|
return getPowerShellFunction();
|
|
136
160
|
case 'bash':
|
|
137
161
|
case 'zsh':
|
|
138
|
-
return getBashFunction();
|
|
162
|
+
return getBashFunction(); // zsh 使用和 bash 相同的语法
|
|
139
163
|
case 'fish':
|
|
140
164
|
return getFishFunction();
|
|
141
165
|
default:
|
|
@@ -174,6 +198,11 @@ function installShellIntegration() {
|
|
|
174
198
|
|
|
175
199
|
const functionCode = getShellFunction(shell);
|
|
176
200
|
|
|
201
|
+
if (!functionCode) {
|
|
202
|
+
console.log('Failed to generate shell integration script');
|
|
203
|
+
return false;
|
|
204
|
+
}
|
|
205
|
+
|
|
177
206
|
if (fs.existsSync(configPath)) {
|
|
178
207
|
const content = fs.readFileSync(configPath, 'utf8');
|
|
179
208
|
fs.writeFileSync(configPath, content + '\n' + functionCode);
|
|
@@ -113,33 +113,48 @@ function removeShellIntegration(configPath, shell) {
|
|
|
113
113
|
|
|
114
114
|
function main() {
|
|
115
115
|
console.log('🧹 fnva shell integration uninstaller');
|
|
116
|
+
console.log('npm install location:', __dirname);
|
|
117
|
+
console.log('Current platform:', process.platform);
|
|
118
|
+
console.log('Detected shell:', process.env.SHELL || 'unknown');
|
|
116
119
|
|
|
117
120
|
const shell = detectShell();
|
|
118
121
|
const paths = getShellConfigPaths(shell);
|
|
119
122
|
|
|
123
|
+
console.log(`Config paths for ${shell}:`, paths);
|
|
124
|
+
|
|
120
125
|
if (!paths.length) {
|
|
121
126
|
console.log(`⚠️ Unsupported shell: ${shell}`);
|
|
127
|
+
console.log('No config files found for this shell');
|
|
122
128
|
return;
|
|
123
129
|
}
|
|
124
130
|
|
|
131
|
+
console.log(`Attempting to clean config files...`);
|
|
125
132
|
const success = removeShellIntegration(null, shell);
|
|
126
133
|
|
|
127
134
|
if (success) {
|
|
135
|
+
console.log('✅ Shell integration successfully removed');
|
|
128
136
|
console.log('🔄 Reload your shell config:');
|
|
129
137
|
switch (shell) {
|
|
130
138
|
case 'powershell':
|
|
131
139
|
console.log(' . $PROFILE');
|
|
140
|
+
console.log(' Or start new PowerShell instance');
|
|
132
141
|
break;
|
|
133
142
|
case 'bash':
|
|
134
143
|
console.log(' source ~/.bashrc');
|
|
144
|
+
console.log(' Or: exec bash');
|
|
135
145
|
break;
|
|
136
146
|
case 'zsh':
|
|
137
147
|
console.log(' source ~/.zshrc');
|
|
148
|
+
console.log(' Or: exec zsh');
|
|
138
149
|
break;
|
|
139
150
|
case 'fish':
|
|
140
151
|
console.log(' source ~/.config/fish/config.fish');
|
|
152
|
+
console.log(' Or: exec fish');
|
|
141
153
|
break;
|
|
142
154
|
}
|
|
155
|
+
} else {
|
|
156
|
+
console.log('⚠️ No fnva shell integration found in any config files');
|
|
157
|
+
console.log(' (This is normal if shell integration was never installed)');
|
|
143
158
|
}
|
|
144
159
|
}
|
|
145
160
|
|