From 1503d40aba8ba2363e68424995117672ca3e83ed Mon Sep 17 00:00:00 2001 From: teknium1 <127238744+teknium1@users.noreply.github.com> Date: Wed, 16 Sep 2026 12:29:21 -0700 Subject: [PATCH] fix(desktop): strip installer escapes from the manifest-failure banner too MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Only Log lines were sanitized at the emitter; the manifest-step error string was still built from the raw child stderr/stdout tail, so a failing `install.sh --manifest` (print_error writes `${RED}✗${NC}`) put escape bytes straight into the Setup failure banner. Run stripAnsi / strip_ansi over the embedded tail on both the Electron and the Tauri bootstrap surfaces (#112675). --- .../src-tauri/src/bootstrap.rs | 2 +- .../desktop/electron/bootstrap-runner.test.ts | 24 +++++++++++++++++++ apps/desktop/electron/bootstrap-runner.ts | 8 ++++--- 3 files changed, 30 insertions(+), 4 deletions(-) diff --git a/apps/bootstrap-installer/src-tauri/src/bootstrap.rs b/apps/bootstrap-installer/src-tauri/src/bootstrap.rs index 783916cd74..8d6d81cb56 100644 --- a/apps/bootstrap-installer/src-tauri/src/bootstrap.rs +++ b/apps/bootstrap-installer/src-tauri/src/bootstrap.rs @@ -583,7 +583,7 @@ async fn run_bootstrap( let err = format!( "install.ps1 -Manifest failed: exit {:?}\n{}", manifest_result.exit_code, - manifest_result.stderr.trim() + crate::events::strip_ansi(manifest_result.stderr.trim()) ); emit_event( &app, diff --git a/apps/desktop/electron/bootstrap-runner.test.ts b/apps/desktop/electron/bootstrap-runner.test.ts index 19fb679fd8..5cc6f92f23 100644 --- a/apps/desktop/electron/bootstrap-runner.test.ts +++ b/apps/desktop/electron/bootstrap-runner.test.ts @@ -289,3 +289,27 @@ test('installer log lines reach the emitter without escape sequences; \\r redraw // Plain multi-byte text is untouched. assert.equal(cleanInstallerLogLine('Ready — café ✓ 中文'), 'Ready — café ✓ 中文') }) + +test.skipIf(process.platform === 'win32')( + 'a manifest-step failure surfaces the installer tail without escape sequences', + async () => { + const home = mkTmpHome() + fs.mkdirSync(path.join(home, 'scripts')) + fs.writeFileSync( + path.join(home, 'scripts', 'install.sh'), + '#!/usr/bin/env bash\nprintf "\\033[0;31m\\xe2\\x9c\\x97\\033[0m manifest broke\\n" >&2\nexit 3\n' + ) + + const result = await runBootstrap({ + installStamp: null, + activeRoot: home, + sourceRepoRoot: home, + hermesHome: home, + logRoot: home, + onEvent: () => {} + }) + + assert.equal(result.ok, false) + assert.equal(result.error, 'install.sh --manifest failed: exit 3\n✗ manifest broke') + } +) diff --git a/apps/desktop/electron/bootstrap-runner.ts b/apps/desktop/electron/bootstrap-runner.ts index dce1713a5f..90b3f55731 100644 --- a/apps/desktop/electron/bootstrap-runner.ts +++ b/apps/desktop/electron/bootstrap-runner.ts @@ -737,9 +737,11 @@ async function fetchManifest({ }) if (result.code !== 0) { - throw new Error( - `${isPosix ? 'install.sh --manifest' : 'install.ps1 -Manifest'} failed: exit ${result.code}\n${result.stderr || result.stdout}` - ) + // The tail lands in the Setup failure banner, not the log ring, so strip + // the installer's colour/OSC bytes here too (#112675). + const tail = stripAnsi(result.stderr || result.stdout).trim() + + throw new Error(`${isPosix ? 'install.sh --manifest' : 'install.ps1 -Manifest'} failed: exit ${result.code}\n${tail}`) } // The manifest is the LAST JSON line on stdout (install.ps1 may print