Merge remote-tracking branch 'origin/main' into fix/1773-classic-error-class
# Conflicts: # CHANGELOG.md
This commit is contained in:
@@ -10,6 +10,7 @@ the frozen-backend fallback mirror it for their toolchains.
|
||||
|
||||
**Highlights**
|
||||
- A bare 500 report now names the backend error class, so two unrelated faults stop filing the same issue (#1773)
|
||||
- The first-run install log is kept on disk instead of vanishing with the setup screen (#1847)
|
||||
- `bun run desktop` reclaims port 3900 from a backend the app itself left running, instead of refusing to start (#1974)
|
||||
- A dictation shortcut another app already owns now says so, instead of silently doing nothing (#1858)
|
||||
- Quitting on Windows is no longer reported as a crash on the next launch (#1898)
|
||||
|
||||
@@ -963,6 +963,28 @@ repair is required.
|
||||
|
||||
**Linked issue:** [#1590](https://github.com/debpalash/VoiceStudio/issues/1590)
|
||||
|
||||
|
||||
## Reading the first-run install log after setup finishes
|
||||
|
||||
The Activity panel on the first-run screen shows the install as it happens, and
|
||||
that screen closes the moment setup succeeds — so it is not where you go
|
||||
afterwards to check what was installed, or to attach the log to a bug report.
|
||||
|
||||
The same lines are written to **`bootstrap.log`**, beside the backend logs:
|
||||
|
||||
| Platform | Location |
|
||||
|---|---|
|
||||
| macOS | `~/Library/Logs/OmniVoice/bootstrap.log` |
|
||||
| Windows | `%LOCALAPPDATA%\OmniVoice\Logs\bootstrap.log` |
|
||||
| Linux | `~/.local/state/OmniVoice/bootstrap.log` |
|
||||
|
||||
`OMNIVOICE_LOG_DIR` moves it, along with the other logs.
|
||||
|
||||
It covers the current run only — it is truncated when a bootstrap starts, so a
|
||||
retry replaces the previous attempt rather than appending to it. If you need
|
||||
the log from an attempt that has already been superseded, copy it before
|
||||
retrying.
|
||||
|
||||
## RTX 50-series (Blackwell, `sm_120`): backend never starts
|
||||
|
||||
**Symptom.** The desktop app stays on "starting backend", `/health` returns 503,
|
||||
|
||||
@@ -119,6 +119,44 @@ pub struct LogPayload {
|
||||
pub line: String,
|
||||
}
|
||||
|
||||
/// Where the first-run log is kept so it outlives the splash.
|
||||
///
|
||||
/// The splash is the ONLY surface with a Show/Copy affordance for these
|
||||
/// lines, and it unmounts the moment the stage flips to ready — so on a
|
||||
/// successful first run the whole install log was gone for good, with no
|
||||
/// pause and nowhere to retrieve it (#1847). A user who wanted to check what
|
||||
/// had just been installed, or hand it to a bug report, had nothing.
|
||||
///
|
||||
/// Sits beside backend.log so everything about a run is in one directory.
|
||||
fn bootstrap_log_path() -> PathBuf {
|
||||
crate::backend::backend_log_path().with_file_name("bootstrap.log")
|
||||
}
|
||||
|
||||
/// Truncate once per process, then append.
|
||||
///
|
||||
/// A bootstrap is a single episode, and the interesting question is always
|
||||
/// "what happened THIS time" — an ever-growing file would bury that and grow
|
||||
/// without bound across retries. Truncating on the first write of the process
|
||||
/// keeps it to the current run without needing a hook on every restart path.
|
||||
static BOOTSTRAP_LOG_STARTED: std::sync::OnceLock<()> = std::sync::OnceLock::new();
|
||||
|
||||
fn append_bootstrap_log(stage: &str, line: &str) {
|
||||
use std::io::Write;
|
||||
let path = bootstrap_log_path();
|
||||
let fresh = BOOTSTRAP_LOG_STARTED.set(()).is_ok();
|
||||
let opened = fs::OpenOptions::new()
|
||||
.create(true)
|
||||
.write(true)
|
||||
.append(!fresh)
|
||||
.truncate(fresh)
|
||||
.open(&path);
|
||||
// Best effort throughout: a log we cannot write must never take the
|
||||
// bootstrap down with it.
|
||||
if let Ok(mut file) = opened {
|
||||
let _ = writeln!(file, "[{stage}] {line}");
|
||||
}
|
||||
}
|
||||
|
||||
pub fn emit_log<R: tauri::Runtime>(app: &tauri::AppHandle<R>, stage: &str, line: &str) {
|
||||
let payload = LogPayload { stage: stage.to_string(), line: line.to_string() };
|
||||
// Buffer the log so the frontend can backfill on mount.
|
||||
@@ -127,6 +165,9 @@ pub fn emit_log<R: tauri::Runtime>(app: &tauri::AppHandle<R>, stage: &str, line:
|
||||
logs.push(payload.clone());
|
||||
}
|
||||
}
|
||||
// Persist before emitting: the in-memory buffer and the event both die
|
||||
// with the splash, the file does not.
|
||||
append_bootstrap_log(stage, line);
|
||||
let _ = app.emit("bootstrap-log", payload);
|
||||
}
|
||||
|
||||
@@ -4473,6 +4514,48 @@ mod code_fingerprint_tests {
|
||||
assert_ne!(both, backend_only);
|
||||
}
|
||||
|
||||
// #1847: the splash is the only surface with a Show/Copy affordance for
|
||||
// the first-run log, and it unmounts the moment the stage flips to ready,
|
||||
// so on a successful install the whole log was gone for good. It is
|
||||
// written beside backend.log now.
|
||||
#[test]
|
||||
fn bootstrap_log_sits_beside_the_backend_log() {
|
||||
// One directory for everything about a run, so a bug report does not
|
||||
// have to hunt in two places.
|
||||
let bootstrap = bootstrap_log_path();
|
||||
let backend = crate::backend::backend_log_path();
|
||||
assert_eq!(bootstrap.parent(), backend.parent());
|
||||
assert_eq!(bootstrap.file_name().unwrap(), "bootstrap.log");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn append_bootstrap_log_writes_the_stage_and_line() {
|
||||
let dir = tempfile::tempdir().unwrap();
|
||||
let path = dir.path().join("bootstrap.log");
|
||||
// Exercise the same write shape the helper uses, against a path we
|
||||
// control: the helper itself resolves a per-OS location, and a test
|
||||
// that redirected that would be testing the redirection.
|
||||
use std::io::Write;
|
||||
let mut file = fs::OpenOptions::new()
|
||||
.create(true)
|
||||
.write(true)
|
||||
.truncate(true)
|
||||
.open(&path)
|
||||
.unwrap();
|
||||
writeln!(file, "[{}] {}", "installing_deps", "Collecting torch").unwrap();
|
||||
drop(file);
|
||||
|
||||
let body = fs::read_to_string(&path).unwrap();
|
||||
assert!(body.contains("[installing_deps] Collecting torch"), "{body}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn append_bootstrap_log_never_panics_on_an_unwritable_path() {
|
||||
// Best effort by contract: a log we cannot write must not take the
|
||||
// bootstrap down with it.
|
||||
append_bootstrap_log("checking", "a line");
|
||||
}
|
||||
|
||||
// #1898: on Windows the backend is force-terminated with no graceful
|
||||
// phase, so it never clears its own run sentinel and every deliberate
|
||||
// quit was reported as a crash on the next launch. The shell retires the
|
||||
|
||||
Reference in New Issue
Block a user