-
Notifications
You must be signed in to change notification settings - Fork 130
fix(windows): 收敛启动和开发产物路径 #48
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,6 +4,7 @@ dist/ | |
| *.local | ||
| .env | ||
| .vite/ | ||
| .artifacts/ | ||
|
|
||
| # Tauri | ||
| src-tauri/target/ | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,39 +1,86 @@ | ||
| param( | ||
| [string]$MirrorRoot = "$env:TEMP\openless-windows-gnu" | ||
| [string]$MirrorRoot = "$env:TEMP\openless-windows-gnu", | ||
| [string]$ArtifactsRoot = "", | ||
| [switch]$KeepMirror | ||
| ) | ||
|
|
||
| $ErrorActionPreference = "Stop" | ||
|
|
||
| $appRoot = (Resolve-Path (Join-Path $PSScriptRoot "..")).Path | ||
| $buildRoot = $appRoot | ||
| $usedMirror = $false | ||
| if ([string]::IsNullOrWhiteSpace($ArtifactsRoot)) { | ||
| $ArtifactsRoot = Join-Path $appRoot ".artifacts\windows-gnu" | ||
| } | ||
|
|
||
| if ($appRoot -match "\s") { | ||
| Write-Host "[info] App path contains spaces: $appRoot" | ||
| Write-Host "[info] Mirroring to no-space build root: $MirrorRoot" | ||
| Write-Host "[info] Mirroring to no-space scratch build root: $MirrorRoot" | ||
| New-Item -ItemType Directory -Force -Path $MirrorRoot | Out-Null | ||
| robocopy $appRoot $MirrorRoot /MIR /XD "$appRoot\node_modules" "$appRoot\dist" "$appRoot\src-tauri\target" "$MirrorRoot\node_modules" "$MirrorRoot\dist" "$MirrorRoot\src-tauri\target" | Out-Host | ||
| robocopy $appRoot $MirrorRoot /MIR /XD "$appRoot\.artifacts" "$appRoot\node_modules" "$appRoot\dist" "$appRoot\src-tauri\target" "$MirrorRoot\.artifacts" "$MirrorRoot\node_modules" "$MirrorRoot\dist" "$MirrorRoot\src-tauri\target" | Out-Host | ||
| if ($LASTEXITCODE -gt 7) { | ||
| throw "robocopy failed with exit code $LASTEXITCODE" | ||
| } | ||
| $buildRoot = (Resolve-Path $MirrorRoot).Path | ||
| $usedMirror = $true | ||
| } | ||
|
|
||
| $env:PATH = "$env:USERPROFILE\.cargo\bin;$env:USERPROFILE\scoop\persist\rustup\.cargo\bin;$env:USERPROFILE\scoop\apps\rustup\current\.cargo\bin;$env:USERPROFILE\scoop\apps\mingw\current\bin;$env:PATH" | ||
| $env:RUSTUP_TOOLCHAIN = "stable-x86_64-pc-windows-gnu" | ||
| $env:CARGO_BUILD_TARGET = "x86_64-pc-windows-gnu" | ||
|
|
||
| function Resolve-WebView2Loader { | ||
| $cargoHome = if ($env:CARGO_HOME) { $env:CARGO_HOME } else { Join-Path $env:USERPROFILE ".cargo" } | ||
| $registrySrc = Join-Path $cargoHome "registry\src" | ||
| $loader = Get-ChildItem -Path $registrySrc -Recurse -Filter WebView2Loader.dll -ErrorAction SilentlyContinue | | ||
| Where-Object { $_.FullName -match "\\x64\\WebView2Loader\.dll$" } | | ||
| Select-Object -First 1 | ||
| if ($null -eq $loader) { | ||
| throw "WebView2Loader.dll x64 not found under $registrySrc" | ||
| } | ||
| return $loader.FullName | ||
| } | ||
|
|
||
| Push-Location $buildRoot | ||
| try { | ||
| if (-not (Test-Path "node_modules")) { | ||
| npm ci | ||
| } | ||
| npm run tauri build -- --target x86_64-pc-windows-gnu | ||
| npm run tauri build -- --target x86_64-pc-windows-gnu --no-bundle | ||
| $releaseRoot = Join-Path $buildRoot "src-tauri\target\x86_64-pc-windows-gnu\release" | ||
| $artifactDevRoot = Join-Path $ArtifactsRoot "dev" | ||
| New-Item -ItemType Directory -Force -Path $artifactDevRoot | Out-Null | ||
| Copy-Item -LiteralPath (Join-Path $releaseRoot "openless.exe") -Destination (Join-Path $artifactDevRoot "openless.exe") -Force | ||
| Copy-Item -LiteralPath (Resolve-WebView2Loader) -Destination (Join-Path $artifactDevRoot "WebView2Loader.dll") -Force | ||
|
|
||
| npm run tauri build -- --target x86_64-pc-windows-gnu --bundles msi nsis | ||
| } finally { | ||
| Pop-Location | ||
| } | ||
|
|
||
| $releaseRoot = Join-Path $buildRoot "src-tauri\target\x86_64-pc-windows-gnu\release" | ||
| $artifactReleaseRoot = Join-Path $ArtifactsRoot "release" | ||
| New-Item -ItemType Directory -Force -Path $artifactReleaseRoot | Out-Null | ||
| Remove-Item -LiteralPath (Join-Path $artifactReleaseRoot "openless.exe") -Force -ErrorAction SilentlyContinue | ||
|
|
||
| if (Test-Path (Join-Path $releaseRoot "bundle")) { | ||
| Copy-Item -LiteralPath (Join-Path $releaseRoot "bundle") -Destination $artifactReleaseRoot -Recurse -Force | ||
| } | ||
|
|
||
| if ($usedMirror -and (-not $KeepMirror)) { | ||
| $resolvedMirror = (Resolve-Path $MirrorRoot).Path | ||
| $resolvedTemp = (Resolve-Path $env:TEMP).Path | ||
| if ($resolvedMirror.StartsWith($resolvedTemp, [System.StringComparison]::OrdinalIgnoreCase) -and | ||
| ((Split-Path $resolvedMirror -Leaf) -eq "openless-windows-gnu")) { | ||
| Write-Host "[info] Removing scratch build root: $resolvedMirror" | ||
| Remove-Item -LiteralPath $resolvedMirror -Recurse -Force | ||
| } else { | ||
| Write-Warning "Refusing to remove unexpected mirror path: $resolvedMirror" | ||
| } | ||
| } | ||
|
|
||
| Write-Host "" | ||
| Write-Host "Windows GNU artifacts:" | ||
| Write-Host "$buildRoot\src-tauri\target\x86_64-pc-windows-gnu\release\openless.exe" | ||
| Write-Host "$buildRoot\src-tauri\target\x86_64-pc-windows-gnu\release\bundle\msi" | ||
| Write-Host "$buildRoot\src-tauri\target\x86_64-pc-windows-gnu\release\bundle\nsis" | ||
| Write-Host "$ArtifactsRoot\dev\openless.exe" | ||
| Write-Host "$artifactReleaseRoot\bundle\msi" | ||
| Write-Host "$artifactReleaseRoot\bundle\nsis" |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,77 @@ | ||
| param( | ||
| [string]$ExePath = "" | ||
| ) | ||
|
|
||
| $ErrorActionPreference = "Stop" | ||
|
|
||
| if ([string]::IsNullOrWhiteSpace($ExePath)) { | ||
| $appRoot = (Resolve-Path (Join-Path $PSScriptRoot "..")).Path | ||
| $ExePath = Join-Path $appRoot ".artifacts\windows-gnu\dev\openless.exe" | ||
| } | ||
|
|
||
| Add-Type @" | ||
| using System; | ||
| using System.Runtime.InteropServices; | ||
|
|
||
| public static class OpenLessWindow { | ||
| [DllImport("user32.dll")] | ||
| public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow); | ||
|
|
||
| [DllImport("user32.dll")] | ||
| public static extern bool SetForegroundWindow(IntPtr hWnd); | ||
| } | ||
| "@ | ||
|
|
||
| function Show-OpenLessWindow($Process) { | ||
| if ($null -eq $Process -or $Process.MainWindowHandle -eq 0) { | ||
| return $false | ||
| } | ||
|
|
||
| # 9 = SW_RESTORE. This restores minimized windows and leaves normal windows visible. | ||
| [OpenLessWindow]::ShowWindow($Process.MainWindowHandle, 9) | Out-Null | ||
| [OpenLessWindow]::SetForegroundWindow($Process.MainWindowHandle) | Out-Null | ||
| return $true | ||
| } | ||
|
|
||
| $running = Get-Process openless -ErrorAction SilentlyContinue | | ||
| Where-Object { $_.MainWindowHandle -ne 0 } | | ||
| Select-Object -First 1 | ||
|
|
||
| if (Show-OpenLessWindow $running) { | ||
| Write-Host "OpenLess is already running; brought window to foreground. pid=$($running.Id)" | ||
| exit 0 | ||
| } | ||
|
|
||
| if (-not (Test-Path $ExePath)) { | ||
| throw "OpenLess executable not found: $ExePath. Run scripts/windows-build-gnu.ps1 first." | ||
| } | ||
|
|
||
| if (-not (Test-Path (Join-Path (Split-Path $ExePath -Parent) "WebView2Loader.dll"))) { | ||
| throw "WebView2Loader.dll not found beside $ExePath. Run scripts/windows-build-gnu.ps1 again." | ||
| } | ||
|
|
||
| if (-not $env:SystemDrive) { | ||
| $env:SystemDrive = "C:" | ||
| } | ||
| if (-not $env:ProgramData) { | ||
| $env:ProgramData = Join-Path $env:SystemDrive "ProgramData" | ||
| } | ||
| $env:PATH = "$env:USERPROFILE\.cargo\bin;$env:USERPROFILE\scoop\persist\rustup\.cargo\bin;$env:USERPROFILE\scoop\apps\rustup\current\.cargo\bin;$env:USERPROFILE\scoop\apps\mingw\current\bin;$env:PATH" | ||
| $env:OPENLESS_SHOW_MAIN_ON_START = "1" | ||
| try { | ||
| $process = Start-Process -FilePath $ExePath -WorkingDirectory (Split-Path $ExePath -Parent) -PassThru | ||
| } finally { | ||
| Remove-Item Env:OPENLESS_SHOW_MAIN_ON_START -ErrorAction SilentlyContinue | ||
| } | ||
| $deadline = (Get-Date).AddSeconds(10) | ||
|
|
||
| while ((Get-Date) -lt $deadline) { | ||
| Start-Sleep -Milliseconds 250 | ||
| $current = Get-Process -Id $process.Id -ErrorAction SilentlyContinue | ||
| if (Show-OpenLessWindow $current) { | ||
| Write-Host "OpenLess started and brought to foreground. pid=$($current.Id)" | ||
| exit 0 | ||
| } | ||
| } | ||
|
|
||
| throw "OpenLess started but no main window was visible within 10 seconds. pid=$($process.Id)" |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,108 @@ | ||
| param( | ||
| [string]$ExePath = "", | ||
| [int]$StartupTimeoutSeconds = 12, | ||
| [switch]$RequireCredentials | ||
| ) | ||
|
|
||
| $ErrorActionPreference = "Stop" | ||
|
|
||
| if ([string]::IsNullOrWhiteSpace($ExePath)) { | ||
| $appRoot = (Resolve-Path (Join-Path $PSScriptRoot "..")).Path | ||
| $ExePath = Join-Path $appRoot ".artifacts\windows-gnu\dev\openless.exe" | ||
| } | ||
|
|
||
| if (-not $env:SystemDrive) { | ||
| $env:SystemDrive = "C:" | ||
| } | ||
| if (-not $env:ProgramData) { | ||
| $env:ProgramData = Join-Path $env:SystemDrive "ProgramData" | ||
| } | ||
|
|
||
| function Test-CredentialValue($Value) { | ||
| return ($null -ne $Value) -and ($Value -is [string]) -and ($Value.Trim().Length -gt 0) | ||
| } | ||
|
|
||
| function Get-OpenLessCredentialStatus { | ||
| $path = Join-Path $env:APPDATA "OpenLess\credentials.json" | ||
| if (-not (Test-Path $path)) { | ||
| return [pscustomobject]@{ | ||
| Path = $path | ||
| VolcengineConfigured = $false | ||
| ArkConfigured = $false | ||
| Present = $false | ||
| } | ||
| } | ||
|
|
||
| $json = Get-Content -Raw $path | ConvertFrom-Json | ||
| $asr = $json.providers.asr.volcengine | ||
| $llm = $json.providers.llm.ark | ||
| [pscustomobject]@{ | ||
| Path = $path | ||
| Present = $true | ||
| VolcengineConfigured = (Test-CredentialValue $asr.appKey) -and (Test-CredentialValue $asr.accessKey) | ||
| ArkConfigured = Test-CredentialValue $llm.apiKey | ||
| } | ||
| } | ||
|
|
||
| function Wait-LogPattern($Path, $Pattern, $TimeoutSeconds) { | ||
| $deadline = (Get-Date).AddSeconds($TimeoutSeconds) | ||
| while ((Get-Date) -lt $deadline) { | ||
| if ((Test-Path $Path) -and ((Get-Content -Raw $Path) -match $Pattern)) { | ||
| return $true | ||
| } | ||
| Start-Sleep -Milliseconds 500 | ||
| } | ||
| return $false | ||
| } | ||
|
|
||
| if (-not (Test-Path $ExePath)) { | ||
| throw "OpenLess executable not found: $ExePath" | ||
| } | ||
|
|
||
| $logPath = Join-Path $env:LOCALAPPDATA "OpenLess\Logs\openless.log" | ||
| $credentialStatus = Get-OpenLessCredentialStatus | ||
|
|
||
| Write-Host "== Credential status ==" | ||
| $credentialStatus | Format-List | ||
| if (-not $credentialStatus.VolcengineConfigured) { | ||
| Write-Host "[warn] Volcengine ASR credentials are not configured; real transcription cannot be completed." | ||
| } | ||
| if (-not $credentialStatus.ArkConfigured) { | ||
| Write-Host "[warn] Ark LLM credentials are not configured; polishing will fall back or fail depending on mode." | ||
| } | ||
| if ($RequireCredentials -and (-not $credentialStatus.VolcengineConfigured -or -not $credentialStatus.ArkConfigured)) { | ||
| throw "Real regression requires configured Volcengine ASR and Ark LLM credentials." | ||
| } | ||
|
|
||
| Write-Host "" | ||
| Write-Host "== Launch smoke ==" | ||
| $process = Start-Process -FilePath $ExePath -PassThru | ||
| try { | ||
| Start-Sleep -Seconds 4 | ||
| $live = Get-Process -Id $process.Id -ErrorAction SilentlyContinue | ||
| if (-not $live) { | ||
| throw "OpenLess exited during startup." | ||
| } | ||
| if (-not $live.Responding) { | ||
| throw "OpenLess process is not responding." | ||
| } | ||
| Write-Host "[ok] Process responding: id=$($live.Id), title='$($live.MainWindowTitle)'" | ||
|
|
||
| if (Wait-LogPattern $logPath "hotkey listener installed" $StartupTimeoutSeconds) { | ||
| Write-Host "[ok] Hotkey listener installed according to log." | ||
| } else { | ||
| throw "Hotkey listener did not report installed within $StartupTimeoutSeconds seconds." | ||
| } | ||
|
|
||
| Write-Host "" | ||
| Write-Host "Manual checks still required:" | ||
| Write-Host "- Press the configured physical global hotkey to start/stop recording." | ||
| Write-Host "- Speak a short phrase with valid ASR credentials configured." | ||
| Write-Host "- Focus Notepad or another text field and verify Windows insert status falls back to copied/Ctrl+V when insertion cannot be confirmed." | ||
| Write-Host "- Toggle Windows microphone privacy off/on and rerun Settings -> Permissions." | ||
| } finally { | ||
| Get-Process openless -ErrorAction SilentlyContinue | Stop-Process -Force | ||
|
Comment on lines
+103
to
+104
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. issue (bug_risk): Stopping all The teardown logic appears to call |
||
| } | ||
|
|
||
| Write-Host "" | ||
| Write-Host "Runtime smoke passed." | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
suggestion: Log polling should tolerate transient read errors on the log file
Here
Get-Content -Raw $Pathcan intermittently fail (e.g. sharing violations during log rotation or exclusive locks), which will terminate the whole smoke script instead of allowing another poll.Consider treating these as transient by adding
-ErrorAction SilentlyContinueor wrapping the read in try/catch and treating failures like a non-match so the loop continues until timeout.