fnva 0.0.10 → 0.0.11
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 +11 -0
- package/bin/fnva.js +158 -15
- package/package.json +1 -1
- package/platforms/fnva +0 -0
- package/platforms/fnva.exe +0 -0
- package/platforms/fnva-0.0.10.tgz +0 -0
package/README.md
CHANGED
|
@@ -28,6 +28,17 @@ yarn global add fnva
|
|
|
28
28
|
|
|
29
29
|
# 使用 pnpm
|
|
30
30
|
pnpm add -g fnva
|
|
31
|
+
|
|
32
|
+
function fnva {
|
|
33
|
+
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") {
|
|
34
|
+
$tempFile = "$env:TEMP\fnva_script_$(Get-Random).ps1"
|
|
35
|
+
& node bin\fnva.js $args | Out-File -FilePath $tempFile -Encoding UTF8
|
|
36
|
+
& $tempFile
|
|
37
|
+
Remove-Item $tempFile -ErrorAction SilentlyContinue
|
|
38
|
+
} else {
|
|
39
|
+
& node bin\fnva.js $args
|
|
40
|
+
}
|
|
41
|
+
}
|
|
31
42
|
```
|
|
32
43
|
|
|
33
44
|
### 方式二:从 Releases 下载二进制文件
|
package/bin/fnva.js
CHANGED
|
@@ -103,6 +103,43 @@ function hasSessionFlag(args) {
|
|
|
103
103
|
return args.includes('--session');
|
|
104
104
|
}
|
|
105
105
|
|
|
106
|
+
function hasApplyFlag(args) {
|
|
107
|
+
return args.includes('--apply');
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function hasAutoExecuteFlag(args) {
|
|
111
|
+
return args.includes('--auto');
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function removeAutoFlag(args) {
|
|
115
|
+
const index = args.indexOf('--auto');
|
|
116
|
+
if (index > -1) {
|
|
117
|
+
return args.slice(0, index).concat(args.slice(index + 1));
|
|
118
|
+
}
|
|
119
|
+
return args;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function createTempScriptFile(script, envType, envName) {
|
|
123
|
+
try {
|
|
124
|
+
const os = require('os');
|
|
125
|
+
const fs = require('fs');
|
|
126
|
+
const path = require('path');
|
|
127
|
+
|
|
128
|
+
const tempDir = os.tmpdir();
|
|
129
|
+
const scriptFile = path.join(tempDir, `fnva_${envType}_${envName}_${Date.now()}.ps1`);
|
|
130
|
+
|
|
131
|
+
fs.writeFileSync(scriptFile, script, 'utf8');
|
|
132
|
+
|
|
133
|
+
console.log('');
|
|
134
|
+
console.log('💡 环境已切换到当前进程。要在新的 PowerShell 窗口中使用此环境,运行:');
|
|
135
|
+
console.log(` ${scriptFile}`);
|
|
136
|
+
console.log(' 或者: fnva', envType, 'use', envName, '--auto');
|
|
137
|
+
|
|
138
|
+
} catch (error) {
|
|
139
|
+
console.warn('⚠️ 无法创建临时脚本文件:', error.message);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
106
143
|
function parseEnvironmentScript(scriptContent) {
|
|
107
144
|
if (!scriptContent || scriptContent.trim() === '') {
|
|
108
145
|
return {};
|
|
@@ -120,10 +157,25 @@ function parseEnvironmentScript(scriptContent) {
|
|
|
120
157
|
const trimmedLine = line.trim();
|
|
121
158
|
|
|
122
159
|
// 解析 PowerShell 环境变量设置
|
|
123
|
-
if (trimmedLine.
|
|
124
|
-
|
|
160
|
+
if (trimmedLine.includes('$env:')) {
|
|
161
|
+
// 匹配 $env:VARNAME = "value" 格式
|
|
162
|
+
let match = trimmedLine.match(/\$env:(\w+)\s*=\s*"([^"]*)"/);
|
|
125
163
|
if (match) {
|
|
126
164
|
envVars[match[1]] = match[2];
|
|
165
|
+
continue;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// 匹配 $env:VARNAME = 'value' 格式
|
|
169
|
+
match = trimmedLine.match(/\$env:(\w+)\s*=\s*'([^']*)'/);
|
|
170
|
+
if (match) {
|
|
171
|
+
envVars[match[1]] = match[2];
|
|
172
|
+
continue;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// 匹配 $env:VARNAME = value 格式(不带引号)
|
|
176
|
+
match = trimmedLine.match(/\$env:(\w+)\s*=\s*([^;]+)/);
|
|
177
|
+
if (match) {
|
|
178
|
+
envVars[match[1]] = match[2].trim().replace(/['"]/g, '');
|
|
127
179
|
}
|
|
128
180
|
}
|
|
129
181
|
|
|
@@ -134,12 +186,6 @@ function parseEnvironmentScript(scriptContent) {
|
|
|
134
186
|
envVars[match[1]] = match[2];
|
|
135
187
|
}
|
|
136
188
|
}
|
|
137
|
-
|
|
138
|
-
// 解析不带引号的环境变量设置
|
|
139
|
-
const unquotedMatch = trimmedLine.match(/\$env:(\w+)\s*=\s*([^;]+)/);
|
|
140
|
-
if (unquotedMatch) {
|
|
141
|
-
envVars[unquotedMatch[1]] = unquotedMatch[2].trim();
|
|
142
|
-
}
|
|
143
189
|
}
|
|
144
190
|
|
|
145
191
|
return envVars;
|
|
@@ -167,6 +213,65 @@ function displaySuccessMessage(envType, envName, envVars) {
|
|
|
167
213
|
}
|
|
168
214
|
}
|
|
169
215
|
|
|
216
|
+
function generateSimpleScript(envVars, envType, envName) {
|
|
217
|
+
const lines = [];
|
|
218
|
+
|
|
219
|
+
if (process.platform === 'win32') {
|
|
220
|
+
// Windows PowerShell
|
|
221
|
+
lines.push(`Write-Host "Switched to ${envType} environment: ${envName}" -ForegroundColor Green`);
|
|
222
|
+
|
|
223
|
+
if (envVars.JAVA_HOME) {
|
|
224
|
+
lines.push(`$env:JAVA_HOME = "${envVars.JAVA_HOME}"`);
|
|
225
|
+
// 对于 PATH,我们需要智能处理:移除旧的 Java 路径,添加新的
|
|
226
|
+
lines.push(`# Remove existing Java paths from PATH`);
|
|
227
|
+
lines.push(`$pathParts = $env:PATH -split ';'`);
|
|
228
|
+
lines.push(`$cleanPath = @()`);
|
|
229
|
+
lines.push(`foreach ($part in $pathParts) {`);
|
|
230
|
+
lines.push(` if ($part -notmatch 'java' -and $part -notmatch 'jdk') {`);
|
|
231
|
+
lines.push(` $cleanPath += $part`);
|
|
232
|
+
lines.push(` }`);
|
|
233
|
+
lines.push(`}`);
|
|
234
|
+
lines.push(`$env:PATH = "${envVars.JAVA_HOME}\\bin;" + ($cleanPath -join ';')`);
|
|
235
|
+
lines.push(`Write-Host "JAVA_HOME: $env:JAVA_HOME" -ForegroundColor Yellow`);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
if (envVars.ANTHROPIC_AUTH_TOKEN) {
|
|
239
|
+
lines.push(`$env:ANTHROPIC_AUTH_TOKEN = "${envVars.ANTHROPIC_AUTH_TOKEN}"`);
|
|
240
|
+
lines.push(`Write-Host "ANTHROPIC_AUTH_TOKEN: [已设置]" -ForegroundColor Yellow`);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
if (envVars.OPENAI_API_KEY) {
|
|
244
|
+
lines.push(`$env:OPENAI_API_KEY = "${envVars.OPENAI_API_KEY}"`);
|
|
245
|
+
lines.push(`Write-Host "OPENAI_API_KEY: [已设置]" -ForegroundColor Yellow`);
|
|
246
|
+
}
|
|
247
|
+
} else {
|
|
248
|
+
// Unix-like systems
|
|
249
|
+
lines.push(`echo "Switched to ${envType} environment: ${envName}"`);
|
|
250
|
+
|
|
251
|
+
if (envVars.JAVA_HOME) {
|
|
252
|
+
lines.push(`export JAVA_HOME="${envVars.JAVA_HOME}"`);
|
|
253
|
+
// 对于 PATH,我们也需要智能处理
|
|
254
|
+
lines.push(`# Remove existing Java paths from PATH`);
|
|
255
|
+
lines.push(`echo $PATH | tr ':' '\\n' | grep -v java | grep -v jdk | tr '\\n' ':' | sed 's/:$//' > /tmp/clean_path`);
|
|
256
|
+
lines.push(`export PATH="${envVars.JAVA_HOME}/bin:$(cat /tmp/clean_path)"`);
|
|
257
|
+
lines.push(`rm -f /tmp/clean_path`);
|
|
258
|
+
lines.push(`echo "JAVA_HOME: $JAVA_HOME"`);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
if (envVars.ANTHROPIC_AUTH_TOKEN) {
|
|
262
|
+
lines.push(`export ANTHROPIC_AUTH_TOKEN="${envVars.ANTHROPIC_AUTH_TOKEN}"`);
|
|
263
|
+
lines.push(`echo "ANTHROPIC_AUTH_TOKEN: [已设置]"`);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
if (envVars.OPENAI_API_KEY) {
|
|
267
|
+
lines.push(`export OPENAI_API_KEY="${envVars.OPENAI_API_KEY}"`);
|
|
268
|
+
lines.push(`echo "OPENAI_API_KEY: [已设置]"`);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
return lines.join('\n');
|
|
273
|
+
}
|
|
274
|
+
|
|
170
275
|
function run() {
|
|
171
276
|
const binaryPath = buildBinaryPath();
|
|
172
277
|
|
|
@@ -180,7 +285,13 @@ function run() {
|
|
|
180
285
|
process.exit(1);
|
|
181
286
|
}
|
|
182
287
|
|
|
183
|
-
|
|
288
|
+
let args = process.argv.slice(2);
|
|
289
|
+
|
|
290
|
+
// 如果设置了 FNVA_AUTO_EXECUTE,则为环境切换命令启用自动执行
|
|
291
|
+
if (process.env.FNVA_AUTO_EXECUTE === '1' && isEnvironmentSwitchCommand(args) && !hasSessionFlag(args)) {
|
|
292
|
+
// 添加 --auto 标志来启用自动执行
|
|
293
|
+
args = args.concat('--auto');
|
|
294
|
+
}
|
|
184
295
|
const isSwitchCommand = isEnvironmentSwitchCommand(args);
|
|
185
296
|
|
|
186
297
|
if (isSwitchCommand) {
|
|
@@ -248,13 +359,45 @@ function run() {
|
|
|
248
359
|
console.log(`📝 Script was: ${script}`);
|
|
249
360
|
}
|
|
250
361
|
} else {
|
|
251
|
-
|
|
252
|
-
if (
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
362
|
+
// 检查是否使用了 --apply 参数
|
|
363
|
+
if (hasApplyFlag(args)) {
|
|
364
|
+
// 直接应用环境变量到当前进程
|
|
365
|
+
const envVars = parseEnvironmentScript(script);
|
|
366
|
+
applyEnvironmentVariables(envVars);
|
|
367
|
+
displaySuccessMessage(envType, envName, envVars);
|
|
256
368
|
} else {
|
|
257
|
-
|
|
369
|
+
// 在 Windows 中,智能处理环境设置
|
|
370
|
+
const envVars = parseEnvironmentScript(script);
|
|
371
|
+
const simpleScript = generateSimpleScript(envVars, envType, envName);
|
|
372
|
+
|
|
373
|
+
// 尝试自动执行(如果可能)
|
|
374
|
+
if (process.env.FNVA_AUTO_EXECUTE === '1') {
|
|
375
|
+
const os = require('os');
|
|
376
|
+
const fs = require('fs');
|
|
377
|
+
const path = require('path');
|
|
378
|
+
const { spawn } = require('child_process');
|
|
379
|
+
|
|
380
|
+
try {
|
|
381
|
+
const tempFile = path.join(os.tmpdir(), `fnva_auto_${Date.now()}.ps1`);
|
|
382
|
+
fs.writeFileSync(tempFile, simpleScript, 'utf8');
|
|
383
|
+
|
|
384
|
+
// 使用 PowerShell 执行脚本
|
|
385
|
+
spawn('powershell', ['-ExecutionPolicy', 'Bypass', '-File', tempFile], {
|
|
386
|
+
stdio: 'inherit',
|
|
387
|
+
shell: false
|
|
388
|
+
}).on('exit', () => {
|
|
389
|
+
try { fs.unlinkSync(tempFile); } catch (_) {}
|
|
390
|
+
});
|
|
391
|
+
|
|
392
|
+
console.log('✅ 环境已自动切换');
|
|
393
|
+
return;
|
|
394
|
+
} catch (error) {
|
|
395
|
+
console.warn('⚠️ 自动执行失败,回退到脚本输出');
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
// 默认输出脚本
|
|
400
|
+
process.stdout.write(simpleScript);
|
|
258
401
|
}
|
|
259
402
|
}
|
|
260
403
|
} else {
|
package/package.json
CHANGED
package/platforms/fnva
CHANGED
|
Binary file
|
package/platforms/fnva.exe
CHANGED
|
Binary file
|
|
Binary file
|