diff --git a/apps/agent/src/config.ts b/apps/agent/src/config.ts index b3b7b30..ea62753 100644 --- a/apps/agent/src/config.ts +++ b/apps/agent/src/config.ts @@ -92,7 +92,10 @@ export function defaultAgentConfig(): AgentConfig { export function loadAgentConfig(): { config: AgentConfig; isNew: boolean } { const p = agentConfigPath(); if (existsSync(p)) { - const cfg = JSON.parse(readFileSync(p, 'utf8')) as AgentConfig; + // 剥离 UTF-8 BOM:Windows 上由 PowerShell 写出的 JSON 可能带 BOM, + // 直接 JSON.parse 会报 "Unexpected token ''" + const text = readFileSync(p, 'utf8').replace(/^\uFEFF/, ''); + const cfg = JSON.parse(text) as AgentConfig; const envKey = process.env['NODEAGENT_KEY']; if (envKey) cfg.key = envKey; return { config: cfg, isNew: false }; diff --git a/packages/client/src/config.ts b/packages/client/src/config.ts index bd5712b..d79a38c 100644 --- a/packages/client/src/config.ts +++ b/packages/client/src/config.ts @@ -85,7 +85,9 @@ function migrate(raw: Record): ClientConfig { export function loadConfig(): ClientConfig | null { const p = configPath(); if (!existsSync(p)) return null; - const raw = JSON.parse(readFileSync(p, 'utf8')) as Record; + // 剥离 UTF-8 BOM(跨平台健壮:某些编辑器 / PowerShell 会写入 BOM) + const text = readFileSync(p, 'utf8').replace(/^\uFEFF/, ''); + const raw = JSON.parse(text) as Record; const cfg = migrate(raw); const envKey = process.env['NODEAGENT_KEY']; const cur = cfg.nodes[cfg.current]; diff --git a/scripts/install.ps1 b/scripts/install.ps1 index 4cd5334..4f7cdb2 100644 --- a/scripts/install.ps1 +++ b/scripts/install.ps1 @@ -105,7 +105,7 @@ if (-not $Key) { Write-Ok "Generated a new pre-shared key" } -@{ +$cfgJson = @{ node_id = $NodeId host = "0.0.0.0" port = $Port @@ -114,7 +114,10 @@ if (-not $Key) { log_level = "info" allow_input = [bool]$AllowInput auth_mode = "psk" -} | ConvertTo-Json | Set-Content -Path $cfgPath -Encoding UTF8 +} | ConvertTo-Json +# 必须写「无 BOM」的 UTF-8:Windows PowerShell 5.1 的 `Set-Content -Encoding UTF8` +# 会写入 BOM(U+FEFF),导致 Node 侧 JSON.parse 报 "Unexpected token ''" +[System.IO.File]::WriteAllText($cfgPath, $cfgJson, (New-Object System.Text.UTF8Encoding($false))) Write-Ok "Config written: $cfgPath" # 5. Firewall (inbound, agent listens)