feat(desktop): lead onboarding with Nous Portal + fix fresh-install detection (#34970)
- Feature Nous Portal as the primary onboarding card (Recommended tag, app logo, single pitch line); collapse other OAuth providers behind an "Other providers" disclosure whose open/closed state persists. - Surface OpenRouter as a one-click API-key option inside the disclosure; move "I have an API key" to a quiet bottom-right link. - Treat "no provider configured" as a normal onboarding state, not a red error banner (provider-setup-errors copy match). - Fix setup.runtime_check: it reported ready when the resolved runtime had an empty credential or only implicit Bedrock/IAM, so fresh installs never saw onboarding. Now requires a usable credential. - Auto-wire Windows fonts for WSL2 users so the renderer renders real Segoe UI instead of the DejaVu fallback; make WSL detection env-independent via the /proc kernel marker.
This commit is contained in:
@@ -1,6 +1,15 @@
|
||||
function isWslEnvironment(env = process.env, platform = process.platform) {
|
||||
const fs = require('node:fs')
|
||||
|
||||
function isWslEnvironment(env = process.env, platform = process.platform, kernelRelease = null) {
|
||||
if (platform !== 'linux') return false
|
||||
return Boolean(env.WSL_DISTRO_NAME || env.WSL_INTEROP)
|
||||
if (env.WSL_DISTRO_NAME || env.WSL_INTEROP) return true
|
||||
|
||||
try {
|
||||
const release = kernelRelease ?? fs.readFileSync('/proc/sys/kernel/osrelease', 'utf8')
|
||||
return /microsoft|wsl/i.test(release)
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
function isWindowsBinaryPathInWsl(filePath, options = {}) {
|
||||
|
||||
@@ -8,7 +8,8 @@ const { bundledRuntimeImportCheck, isWindowsBinaryPathInWsl, isWslEnvironment }
|
||||
test('isWslEnvironment detects WSL2 env vars on linux', () => {
|
||||
assert.equal(isWslEnvironment({ WSL_DISTRO_NAME: 'Ubuntu' }, 'linux'), true)
|
||||
assert.equal(isWslEnvironment({ WSL_INTEROP: '/run/WSL/123_interop' }, 'linux'), true)
|
||||
assert.equal(isWslEnvironment({}, 'linux'), false)
|
||||
assert.equal(isWslEnvironment({}, 'linux', '6.6.87.2-microsoft-standard-WSL2'), true)
|
||||
assert.equal(isWslEnvironment({}, 'linux', '6.6.87-generic'), false)
|
||||
assert.equal(isWslEnvironment({ WSL_DISTRO_NAME: 'Ubuntu' }, 'darwin'), false)
|
||||
})
|
||||
|
||||
|
||||
@@ -490,6 +490,44 @@ function openExternalUrl(rawUrl) {
|
||||
return true
|
||||
}
|
||||
|
||||
function ensureWslWindowsFonts() {
|
||||
if (!IS_WSL) return
|
||||
|
||||
const fontsDir = ['/mnt/c/Windows/Fonts', '/mnt/c/windows/fonts'].find(candidate => {
|
||||
try {
|
||||
return fs.statSync(candidate).isDirectory()
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
})
|
||||
if (!fontsDir) return
|
||||
|
||||
try {
|
||||
const confDir = path.join(app.getPath('home'), '.config', 'fontconfig', 'conf.d')
|
||||
const confPath = path.join(confDir, '99-hermes-wsl-windows-fonts.conf')
|
||||
let existing = ''
|
||||
try {
|
||||
existing = fs.readFileSync(confPath, 'utf8')
|
||||
} catch {
|
||||
existing = ''
|
||||
}
|
||||
if (existing.includes(fontsDir)) return
|
||||
|
||||
fs.mkdirSync(confDir, { recursive: true })
|
||||
fs.writeFileSync(
|
||||
confPath,
|
||||
`<?xml version="1.0"?>\n<!DOCTYPE fontconfig SYSTEM "fonts.dtd">\n<fontconfig>\n <dir>${fontsDir}</dir>\n</fontconfig>\n`
|
||||
)
|
||||
rememberLog(`[fonts] wired WSL Windows fonts for renderer: ${fontsDir}`)
|
||||
|
||||
const cache = spawn('fc-cache', ['-f', fontsDir], { detached: true, stdio: 'ignore' })
|
||||
cache.on('error', () => undefined)
|
||||
cache.unref()
|
||||
} catch (error) {
|
||||
rememberLog(`[fonts] WSL font setup skipped: ${error.message}`)
|
||||
}
|
||||
}
|
||||
|
||||
function sleep(ms) {
|
||||
return new Promise(resolve => setTimeout(resolve, ms))
|
||||
}
|
||||
@@ -1341,9 +1379,7 @@ function resolveHermesBackend(dashboardArgs) {
|
||||
shell: false
|
||||
}
|
||||
}
|
||||
rememberLog(
|
||||
`Ignoring system Python ${python}: hermes_cli is not importable; falling through to bootstrap.`
|
||||
)
|
||||
rememberLog(`Ignoring system Python ${python}: hermes_cli is not importable; falling through to bootstrap.`)
|
||||
}
|
||||
|
||||
// 6. Nothing usable yet -- signal the bootstrap runner that we need to
|
||||
@@ -3296,6 +3332,7 @@ app.whenReady().then(() => {
|
||||
Menu.setApplicationMenu(null)
|
||||
}
|
||||
installMediaPermissions()
|
||||
ensureWslWindowsFonts()
|
||||
createWindow()
|
||||
|
||||
app.on('activate', () => {
|
||||
|
||||
Reference in New Issue
Block a user