studio: unify Windows installer/setup logging style, verbosity controls, and startup messaging#4651
Conversation
for more information, see https://pre-commit.ci
Resolve merge conflicts in setup.sh and setup.ps1 while preserving both main's behavioral additions and the PR's styling refactor: setup.sh: - Keep main's _run_quiet/run_quiet/run_quiet_no_exit architecture with PR's step() styled error messages - Restore REQUESTED_PYTHON_VERSION support from main (install.sh contract) with substep() output style - Restore graceful run_quiet_no_exit || BUILD_OK=false for llama.cpp clone/cmake/build steps (instead of hard exit) - Keep PR's try_quiet for optional llama-quantize step - Keep PR's compact python version check one-liners setup.ps1: - Restore main's cpu-first/CUDA-else PyTorch install structure with PR's step/substep/verbose styling - Combine main's conda+URL detail in Python-not-found error with PR's step/substep format - Style main's stale-venv and conda-skip messages to match PR conventions Auto-merged from main (no conflicts): - _platform_compat import and UTF-8 reconfigure in run.py - Test-IsConda, py.exe launcher, Get-Command -All Python discovery - Stale-venv rebuild logic - Get-PytorchCudaTag with cu118/cpu fallbacks
- Bracket IPv6 display_host in external_url to produce clickable URLs - Redirect try_quiet failure log to stderr instead of stdout - Clamp _step label to column width to prevent negative padding
for more information, see https://pre-commit.ci
Simulation harness (tests/simulate_pr4494.py) creates an isolated uv venv, copies the real source files into it, and runs subprocess tests for all three fixes with visual before/after demos and edge cases. Standalone bash test (tests/test_try_quiet.sh) validates try_quiet stderr redirect across 8 scenarios including broken-version contrast. 39 integration tests total (14 IPv6 + 15 try_quiet + 10 _step), all existing 75 unit tests still pass.
for more information, see https://pre-commit.ci
The %-15s printf format pads short labels but does not truncate long ones. Change to %-15.15s so labels wider than 15 chars are clipped, matching the PowerShell .Substring(0,15) and Python label[:15] logic.
These test files are not part of the styling fix and should not ship with this PR.
Resolve conflicts in install_python_stack.py: keep the PR's column- layout output system (_step, _COL, _LABEL) and incorporate main's _safe_print Unicode fallback for Windows consoles.
- install_python_stack.py: restore _red for patch_package_file warnings (was downgraded to _dim) - setup.ps1: capture winget output and show on failure for CUDA, Node, Python, and OpenSSL installs (was piped to Out-Null) - setup.ps1: always show git pull failure warning, not just in verbose mode
Same capture-and-print-on-failure pattern already used for Node, Python, CUDA, and OpenSSL winget installs.
Resolve conflicts in studio/setup.sh, studio/setup.ps1, and unsloth_cli/commands/studio.py by taking main's logic as the base and applying the PR's styling changes (colors, step/substep helpers, banner/footer) on top. - setup.sh: kept main's Vite 8 node checks, bun install, prebuilt llama.cpp, Colab venv, ROCm support, version skip logic. Applied PR's color palette, step()/substep() helpers, styled banner/footer, and converted status messages. - setup.ps1: kept main's full logic (stop command, update command, prebuilt llama.cpp, etc.). Added PR's VT/ANSI infrastructure (Enable-StudioVirtualTerminal, Get-StudioAnsi, step, substep), styled banner/footer, and converted key status messages. - studio.py: took main's version entirely (stop, _run_setup_script, deprecated setup, update commands). The PR's --verbose flag is a feature addition beyond styling scope.
The step() helper writes to stdout, but _run_quiet's error header was originally sent to stderr (>&2). Without the redirect, callers that separate stdout/stderr would miss the failure headline while still seeing the log body on stderr. Add >&2 to both step calls inside _run_quiet to match main's behavior.
Wire UNSLOTH_VERBOSE=1 through _run_setup_script() so that 'unsloth studio update --verbose' (and the deprecated 'setup') passes the flag to setup.sh / setup.ps1 / install_python_stack.py.
Fail fast when bash is unavailable before invoking setup.sh, and replace remaining nvidia-smi pipeline checks with stream redirection patterns that preserve reliable native exit-code handling.
Ensure PowerShell wrapper helpers in install/update stream native command output to host without returning it as function output, so npm logs no longer corrupt exit-code checks in verbose mode.
|
/gemini review |
There was a problem hiding this comment.
Code Review
This pull request unifies logging and verbosity controls across the installation and setup scripts for Windows and Linux/macOS by introducing standardized logging functions, a verbose flag, and centralized command execution helpers. The changes also refine exception handling in the Python backend and implement tracking for degraded installation states. Feedback was provided regarding code duplication in the install.ps1 script, suggesting a refactor to improve maintainability.
| } elseif ($StudioLocalInstall) { | ||
| uv pip install --python $VenvPython --upgrade-package unsloth "unsloth>=2026.3.14" unsloth-zoo | ||
| Write-Host "==> Overlaying local repo (editable)..." | ||
| uv pip install --python $VenvPython -e $RepoRoot --no-deps | ||
| $baseInstallExit = Invoke-InstallCommand { uv pip install --python $VenvPython --upgrade-package unsloth "unsloth>=2026.3.14" unsloth-zoo } | ||
| } else { | ||
| uv pip install --python $VenvPython --upgrade-package unsloth "$PackageName" | ||
| $baseInstallExit = Invoke-InstallCommand { uv pip install --python $VenvPython --upgrade-package unsloth "$PackageName" } | ||
| } | ||
| if ($baseInstallExit -ne 0) { | ||
| Write-Host "[ERROR] Failed to install unsloth (exit code $baseInstallExit)" -ForegroundColor Red | ||
| return | ||
| } | ||
|
|
||
| if ($StudioLocalInstall) { | ||
| substep "overlaying local repo (editable)..." | ||
| $overlayExit = Invoke-InstallCommand { uv pip install --python $VenvPython -e $RepoRoot --no-deps } | ||
| if ($overlayExit -ne 0) { | ||
| Write-Host "[ERROR] Failed to overlay local repo (exit code $overlayExit)" -ForegroundColor Red | ||
| return | ||
| } | ||
| } |
There was a problem hiding this comment.
This block of code for installing unsloth and overlaying the local repo appears to be duplicated within the elseif ($TorchIndexUrl) block. Consider refactoring to avoid repetition and improve maintainability. You have similar logic for if ($SkipTorch) and elseif ($StudioLocalInstall) and then a general else block, followed by another if ($StudioLocalInstall) block. This could be streamlined.
… verbose - setup.sh: Do not exit non-zero when llama.cpp is unavailable; the footer already reports the limitation, and install.sh runs under set -e so a non-zero exit aborts the entire install including PATH/shortcuts/launch. - setup.ps1: Remove $? check in Invoke-SetupCommand verbose path; PS 5.1 sets $? = $false when native commands write to stderr even with exit 0. Merge stderr into stdout with 2>&1 and rely solely on $LASTEXITCODE. - startup_banner.py: Show the actual bound address when Studio is bound to a non-loopback interface instead of always showing 127.0.0.1/localhost. - setup.sh: Use run_quiet_no_exit instead of run_quiet_no_exit_always for npm install steps so --verbose correctly surfaces npm output.
…one verbose - install.ps1: Apply same Invoke-InstallCommand fix as setup.ps1 -- merge stderr into stdout with 2>&1 and drop the $? check that misclassifies successful native commands on PS 5.1. - install.ps1 + setup.ps1: Export UNSLOTH_VERBOSE=1 to the process env when --verbose is passed so child processes like install_python_stack.py also run in verbose mode. - setup.sh: Use run_quiet_no_exit for git clone llama.cpp so --verbose correctly surfaces clone diagnostics during source-build fallback.
…fix banner - setup.sh: Use tee in verbose mode for prebuilt llama.cpp installer so users can see download/validation progress while still capturing the log for structured error reporting on failure. - setup.ps1: Same fix for Windows -- use Tee-Object in verbose mode. - setup.sh: Remove run_quiet_no_exit_always() which has no remaining callers. - startup_banner.py: Avoid printing the same URL twice when Studio is bound to a specific non-loopback address that matches the display host.
danielhanchen
left a comment
There was a problem hiding this comment.
Thank you for the PR! The goal of this PR is to standardize Studio installer/setup logging across Windows and Linux, add explicit verbose mode controls, and update the startup banner messaging. As a summary, this PR replaces mixed legacy-style status strings with shared step/substep formatting, threads --verbose / UNSLOTH_VERBOSE through the CLI and child processes, and moves the startup banner into a reusable Python helper.
I pushed several fix commits directly to the branch after running 3 rounds of automated review (15 independent reviewers total). Here is the consolidated summary of issues found and fixed:
| Reviewers | Severity | Finding | Status |
|---|---|---|---|
| 15/15 | High | setup.sh exits non-zero for degraded llama.cpp installs, aborting the entire install.sh flow under set -e |
Fixed -- replaced exit 1 with a comment explaining why degraded installs must stay successful |
| 13/15 | High | install.ps1 Invoke-InstallCommand verbose wrapper treats stderr-on-success as failure on PS 5.1 |
Fixed -- merged stderr into stdout with 2>&1 and dropped the $? check, matching setup.ps1 |
| 10/15 | High | Prebuilt llama.cpp installer output suppressed even in verbose mode (Linux + Windows) | Fixed -- use tee/Tee-Object in verbose mode so users see live progress while still capturing the log |
| 6/15 | Medium | UNSLOTH_VERBOSE not exported in install.ps1, setup.ps1 -- child processes like install_python_stack.py stay quiet |
Fixed -- added $env:UNSLOTH_VERBOSE = '1' export when --verbose is set |
| 5/15 | Medium | install.sh UNSLOTH_VERBOSE assigned but never exported |
Fixed in earlier commit |
| 5/15 | Medium | install.sh verbose branch in run_install_cmd runs bare "$@" under set -e -- structured error message never shown |
Fixed in earlier commit |
| 8/15 | Medium | Startup banner shows wrong URLs for non-loopback and IPv6 binds | Fixed -- use actual bound address instead of always defaulting to 127.0.0.1/localhost |
| 8/15 | Medium | --silent flag on first-run launch hides startup banner and port-conflict notice |
Fixed in earlier commit |
| 5/15 | Low | npm install and git clone llama.cpp still suppressed in verbose mode via run_quiet_no_exit_always |
Fixed -- switched to run_quiet_no_exit and removed the unused run_quiet_no_exit_always helper |
| 3/15 | Low | cmake build steps used run_quiet_no_exit_always instead of run_quiet_no_exit |
Fixed in earlier commit |
| 2/15 | Low | Duplicate "Bound address" URL shown when bind host matches display host | Fixed -- added guard condition |
| 1/15 | Info | Duplicate comment line in install.ps1 ("Tell setup.ps1 to skip base package installation") |
Fixed |
All merge conflicts with origin/main have been resolved (kept PR's logging wrappers, updated version pins to 2026.3.16).
The previous pattern 'if "$@"; then return 0; fi; _rc=$?' always captured $? = 0 because $? reflects the if-statement result, not the command's exit code. Switch to '"$@" && return 0; _rc=$?' which preserves the actual command exit code on failure. Applies to both verbose and quiet branches.
|
/gemini review |
There was a problem hiding this comment.
Code Review
This pull request refactors the installation and setup scripts for Windows and Unix-like systems to provide a cleaner, more standardized user interface and improved diagnostic capabilities. Key enhancements include a new verbose mode that propagates to child processes, refined exception handling in Python components, and a graceful degradation mechanism that allows the installation to proceed even if the llama.cpp build fails. I have no feedback to provide as the existing comments were purely explanatory or validating.
- setup.sh: Fix _run_quiet verbose path that always captured exit code 0 due to $? resetting after if-then-fi with no else. Switch to the same '"$@" && return 0; exit_code=$?' pattern used in install.sh. - setup.sh: Consolidate the two uv install branches (verbose + quiet) into a single attempt with conditional output. Previously, when verbose mode was on and the install failed, a second silent attempt was made. - install.ps1: Pass --local flag to 'unsloth studio update' when $StudioLocalInstall is true. Without this, studio.py's update() command overwrites STUDIO_LOCAL_INSTALL to "0", which could cause issues if setup.ps1 or install_python_stack.py later checks that variable.
- Revert SKIP_STUDIO_BASE from 0 to 1 for --no-torch. install.sh already installs unsloth+unsloth-zoo and no-torch-runtime.txt before calling setup.sh, so letting install_python_stack.py redo it was redundant and slowed down --no-torch installs for no benefit. - Restore the "Unsloth Studio installed!" success banner and "starting Unsloth Studio..." launch message so users get clear install completion feedback before the server starts.
…ose + degraded footer - Keep main's PyPI version-check optimization ($SkipPythonDeps) that skips Python dependency work when the installed version already matches latest. - Keep PR's verbose-aware pip upgrade inside the $SkipPythonDeps guard. - Combine main's dynamic $DoneLabel with PR's degraded llama.cpp variant in the footer so both "Setup Complete"/"Updated" and the llama.cpp limitation warning are shown correctly.
- setup.sh: Restore exit 1 when _LLAMA_CPP_DEGRADED is true. GGUF inference requires a working llama.cpp build, so this should be a hard failure, not a silent degradation. - install.sh: Catch setup.sh's non-zero exit with '|| _SETUP_EXIT=$?' instead of letting set -e abort immediately. This ensures PATH setup, symlinks, and shortcuts still get created so the user can fix the build deps and retry with 'unsloth studio update'. After post-install steps, propagate the failure with a clear error message.
'studio update' pops SKIP_STUDIO_BASE from the environment, which defeats the fast-path version check added in PR unslothai#4667. When called from install.ps1 (which already installed packages), SKIP_STUDIO_BASE=1 must survive into setup.ps1 so it skips the redundant PyPI check and package reinstallation. 'studio setup' does not modify env vars.
install.ps1 uses 'studio setup' (not 'studio update') to preserve SKIP_STUDIO_BASE. The deprecation message was confusing during first install since the user never typed the command.
…nslothai#4651 - install.ps1: Always set STUDIO_LOCAL_INSTALL and clear STUDIO_LOCAL_REPO when not using --local, to prevent stale values from a previous --local run in the same PowerShell session. Fix log messages to say 'setup' not 'update' since we call 'studio setup'. - setup.sh: Only exit non-zero for degraded llama.cpp when called from the installer (SKIP_STUDIO_BASE=1). Direct 'unsloth studio update' keeps degraded installs successful since Studio is still usable for non-GGUF workflows and the footer already reports the limitation. - install.sh: Make the setup failure error message generic instead of GGUF-specific, so unrelated failures (npm, Python deps) do not show misleading cmake/git recovery advice.
danielhanchen
left a comment
There was a problem hiding this comment.
Round 4 review (5 independent reviewers). Fixed 3 real issues, dismissed 2 false positives.
| Reviewers | Severity | Finding | Status |
|---|---|---|---|
| 4/5 | High | install.ps1 does not clear stale STUDIO_LOCAL_INSTALL / STUDIO_LOCAL_REPO from previous --local runs in the same PS session |
Fixed -- always set STUDIO_LOCAL_INSTALL and clear STUDIO_LOCAL_REPO when not --local |
| 4/5 | High | setup.sh exit 1 for degraded llama.cpp fires on direct unsloth studio update too, not just installer |
Fixed -- gated on SKIP_STUDIO_BASE=1 so only the installer path triggers it |
| 1/5 | High | install.sh error message assumes GGUF failure for any setup.sh exit |
Fixed -- generic error message pointing to output above |
| 1/5 | High | Colab falls through to llama.cpp setup | False positive -- main has the same behavior, the comment says "continue to llama.cpp install so GGUF inference is available" |
| 2/5 | Medium | bash preflight in install.sh runs too late |
False positive -- install.sh is a bash script, so if bash is missing it cannot run at all |
| 4/5 | Info | Log says "running unsloth studio update" but calls studio setup |
Fixed -- log now says "setup" |
|
/gemini review |
There was a problem hiding this comment.
Code Review
This pull request unifies the installation and setup experience for Unsloth Studio by standardizing logging, output styling, and error handling across PowerShell and Bash scripts. It introduces a verbose mode, ANSI color support, and refined logic for dependency verification and llama.cpp builds. The review feedback suggests enhancing the PowerShell command wrappers to display captured output upon failure in quiet mode, ensuring functional parity with the newly implemented shell script logging behavior.
| function Invoke-InstallCommand { | ||
| param( | ||
| [Parameter(Mandatory = $true)][ScriptBlock]$Command | ||
| ) | ||
| $prevEap = $ErrorActionPreference | ||
| $ErrorActionPreference = "Continue" | ||
| try { | ||
| # Reset to avoid stale values from prior native commands. | ||
| $global:LASTEXITCODE = 0 | ||
| if ($script:UnslothVerbose) { | ||
| # Merge stderr into stdout so progress/warning output stays visible | ||
| # without flipping $? on successful native commands (PS 5.1 treats | ||
| # stderr records as errors that set $? = $false even on exit code 0). | ||
| & $Command 2>&1 | Out-Host | ||
| } else { | ||
| & $Command *> $null | ||
| } | ||
| return [int]$LASTEXITCODE | ||
| } finally { | ||
| $ErrorActionPreference = $prevEap | ||
| } | ||
| } |
There was a problem hiding this comment.
To improve debugging on failure, this function should display the captured output when a command fails in quiet mode. This aligns with the behavior of run_install_cmd in install.sh, which was also introduced in this PR to unify logging behavior.
function Invoke-InstallCommand {
param(
[Parameter(Mandatory = $true)][ScriptBlock]$Command
)
$prevEap = $ErrorActionPreference
$ErrorActionPreference = "Continue"
try {
# Reset to avoid stale values from prior native commands.
$global:LASTEXITCODE = 0
if ($script:UnslothVerbose) {
# Merge stderr into stdout so progress/warning output stays visible
# without flipping $? on successful native commands (PS 5.1 treats
# stderr records as errors that set $? = $false even on exit code 0).
& $Command 2>&1 | Out-Host
} else {
$output = & $Command 2>&1 | Out-String
if ($LASTEXITCODE -ne 0) {
Write-Host $output -ForegroundColor Red
}
}
return [int]$LASTEXITCODE
} finally {
$ErrorActionPreference = $prevEap
}
}
| function Invoke-SetupCommand { | ||
| param( | ||
| [Parameter(Mandatory = $true)][scriptblock]$Command, | ||
| [switch]$AlwaysQuiet | ||
| ) | ||
| $prevEap = $ErrorActionPreference | ||
| $ErrorActionPreference = "Continue" | ||
| try { | ||
| # Reset to avoid stale values from prior native commands. | ||
| $global:LASTEXITCODE = 0 | ||
| if ($script:UnslothVerbose -and -not $AlwaysQuiet) { | ||
| # Merge stderr into stdout so progress/warning output stays visible | ||
| # without flipping $? on successful native commands (PS 5.1 treats | ||
| # stderr records as errors that set $? = $false even on exit code 0). | ||
| & $Command 2>&1 | Out-Host | ||
| } else { | ||
| & $Command *> $null | ||
| } | ||
| return [int]$LASTEXITCODE | ||
| } finally { | ||
| $ErrorActionPreference = $prevEap | ||
| } | ||
| } |
There was a problem hiding this comment.
To improve debugging on failure, this function should display the captured output when a command fails in quiet mode. This aligns with the behavior of run_install_cmd in install.sh and would make the PowerShell scripts more consistent with the PR's goal of unifying logging.
function Invoke-SetupCommand {
param(
[Parameter(Mandatory = $true)][scriptblock]$Command,
[switch]$AlwaysQuiet
)
$prevEap = $ErrorActionPreference
$ErrorActionPreference = "Continue"
try {
# Reset to avoid stale values from prior native commands.
$global:LASTEXITCODE = 0
if ($script:UnslothVerbose -and -not $AlwaysQuiet) {
# Merge stderr into stdout so progress/warning output stays visible
# without flipping $? on successful native commands (PS 5.1 treats
# stderr records as errors that set $? = $false even on exit code 0).
& $Command 2>&1 | Out-Host
} else {
$output = & $Command 2>&1 | Out-String
if ($LASTEXITCODE -ne 0) {
Write-Host $output -ForegroundColor Red
}
}
return [int]$LASTEXITCODE
} finally {
$ErrorActionPreference = $prevEap
}
}
Both Invoke-InstallCommand (install.ps1) and Invoke-SetupCommand (setup.ps1) now capture command output in quiet mode and display it in red when the command fails. This matches the behavior of run_install_cmd in install.sh where failure output is surfaced even in quiet mode, making cross-platform error debugging consistent.
…or PR unslothai#4651 - setup.ps1: Exit non-zero for degraded llama.cpp when called from install.ps1 (SKIP_STUDIO_BASE=1), matching setup.sh behavior. Direct 'unsloth studio update' keeps degraded installs successful. - install.sh: Show 'unsloth studio update --local' in the recovery message when the install was run with --local, so users retry with the correct flag instead of losing local checkout context.
danielhanchen
left a comment
There was a problem hiding this comment.
Round 5 review (5 independent reviewers). Fixed 2 real issues, dismissed 3 false positives.
| Reviewers | Severity | Finding | Status |
|---|---|---|---|
| 3/5 | High | Windows setup.ps1 does not exit non-zero for degraded llama.cpp, unlike Linux setup.sh | Fixed -- added exit 1 gated on SKIP_STUDIO_BASE=1 to match setup.sh |
| 2/5 | High | Recovery message shows unsloth studio update even for --local installs |
Fixed -- shows --local flag when appropriate |
| 1/5 | High | install.sh shebang /bin/sh conflicts with bash requirement | False positive -- install.sh has no shebang, the bash check guards bash "$SETUP_SH" not the installer itself |
| 2/5 | Medium | UNSLOTH_VERBOSE env leak across runs | False positive -- process-scoped, dies with the session |
| 1/5 | Medium | Out-String buffers memory in quiet mode | False positive -- standard PS pattern, negligible overhead |
|
/gemini review |
There was a problem hiding this comment.
Code Review
This pull request implements a unified verbose logging system and a consistent UI style across the installation and setup scripts for both Windows and Unix-like systems. Key changes include the introduction of step and substep functions for standardized output, improved error reporting for llama.cpp builds, and the addition of a --verbose flag to control command output. A logic error was identified in the startup banner's URL display logic, where a condition meant to show the bound address was rendered unreachable.
| ] | ||
| ) | ||
| elif not listen_all and bind_host not in ("127.0.0.1", "localhost", "::1"): | ||
| elif not listen_all and not loopback_bind and external_url != primary_url: |
There was a problem hiding this comment.
The condition to display the 'Bound address' for specific non-loopback IP bindings appears to be incorrect. The external_url != primary_url part of the elif statement will always evaluate to false when not listen_all and not loopback_bind is true, because primary_url is assigned external_url in that case. This makes the block unreachable, preventing the bound address from being displayed when it should be.
| elif not listen_all and not loopback_bind and external_url != primary_url: | |
| elif not listen_all and not loopback_bind: |
…ls, and startup messaging (unslothai#4651) * refactor(studio): unify setup terminal output style and add verbose setup mode * studio(windows): align setup.ps1 banner/steps with setup.sh (ANSI, verbose) * studio(setup): revert nvcc path reordering to match main * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * studio(setup): restore fail-fast llama.cpp setup flow * studio(banner): use IPv6 loopback URL when binding :: or ::1 * Fix IPv6 URL bracketing, try_quiet stderr, _step label clamp - Bracket IPv6 display_host in external_url to produce clickable URLs - Redirect try_quiet failure log to stderr instead of stdout - Clamp _step label to column width to prevent negative padding * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Add sandbox integration tests for PR unslothai#4494 UX fixes Simulation harness (tests/simulate_pr4494.py) creates an isolated uv venv, copies the real source files into it, and runs subprocess tests for all three fixes with visual before/after demos and edge cases. Standalone bash test (tests/test_try_quiet.sh) validates try_quiet stderr redirect across 8 scenarios including broken-version contrast. 39 integration tests total (14 IPv6 + 15 try_quiet + 10 _step), all existing 75 unit tests still pass. * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Truncate step() labels in setup.sh to match PS1 and Python The %-15s printf format pads short labels but does not truncate long ones. Change to %-15.15s so labels wider than 15 chars are clipped, matching the PowerShell .Substring(0,15) and Python label[:15] logic. * Remove sandbox integration tests from PR These test files are not part of the styling fix and should not ship with this PR. * Show error output on failure instead of suppressing it - install_python_stack.py: restore _red for patch_package_file warnings (was downgraded to _dim) - setup.ps1: capture winget output and show on failure for CUDA, Node, Python, and OpenSSL installs (was piped to Out-Null) - setup.ps1: always show git pull failure warning, not just in verbose mode * Show winget error output for Git and CMake installs on failure Same capture-and-print-on-failure pattern already used for Node, Python, CUDA, and OpenSSL winget installs. * fix: preserve stderr for _run_quiet error messages in setup.sh The step() helper writes to stdout, but _run_quiet's error header was originally sent to stderr (>&2). Without the redirect, callers that separate stdout/stderr would miss the failure headline while still seeing the log body on stderr. Add >&2 to both step calls inside _run_quiet to match main's behavior. * feat: add --verbose flag to setup and update commands Wire UNSLOTH_VERBOSE=1 through _run_setup_script() so that 'unsloth studio update --verbose' (and the deprecated 'setup') passes the flag to setup.sh / setup.ps1 / install_python_stack.py. * fix(studio): honor verbose logging and keep llama.cpp failures non-blocking * fix(studio): switch installer to 'studio update' and normalize Windows setup logs * chore(studio): refine localhost tip and remove skip-base setup nois * fix(studio): align Windows setup logs with Linux style and improve startup tips * fix(studio): align Windows setup logs with Linux style * refactor(windows-installer): align install/setup logs with Linux style and silence auto-launch output * refactor(windows): align installer/setup output with Linux style and reduce default verbosity * refactor(windows): match install.ps1 output style/colors to setup and quiet default logs * fix(studio-banner): update personal-computer localhost tip * fix(setup.sh): restore verbose llama.cpp build output while keeping default quiet mode * fix(install.sh): align installer logging with setup style and restore POSIX-safe color output * fix(install.sh): preserve installer reliability and launch visibility Export verbose mode for child setup processes, harden install command handling under set -e, and keep first-run studio launch non-silent so users can always see URL and port fallback output. * fix(windows installer): keep exit semantics and degrade status accurate Use quiet command redirection that preserves native exit codes, keep startup output visible on first launch, and report limited install status when llama.cpp is unavailable. * fix(setup.sh): improve log clarity and enforce GGUF degraded signaling Restore clean default setup output, add verbose-only diagnostics, fail fast on Colab dependency install errors, and return non-zero when GGUF prerequisites or llama.cpp artifacts are unavailable. * fix(installer): harden bash preflight and PowerShell GPU checks Fail fast when bash is unavailable before invoking setup.sh, and replace remaining nvidia-smi pipeline checks with stream redirection patterns that preserve reliable native exit-code handling. * fix(windows): keep verbose output visible while preserving exit codes Ensure PowerShell wrapper helpers in install/update stream native command output to host without returning it as function output, so npm logs no longer corrupt exit-code checks in verbose mode. * fix(windows): avoid sticky UNSLOTH_VERBOSE and gate studio update verbosity * Fix degraded llama.cpp exit code, PS verbose stderr, banner URLs, npm verbose - setup.sh: Do not exit non-zero when llama.cpp is unavailable; the footer already reports the limitation, and install.sh runs under set -e so a non-zero exit aborts the entire install including PATH/shortcuts/launch. - setup.ps1: Remove $? check in Invoke-SetupCommand verbose path; PS 5.1 sets $? = $false when native commands write to stderr even with exit 0. Merge stderr into stdout with 2>&1 and rely solely on $LASTEXITCODE. - startup_banner.py: Show the actual bound address when Studio is bound to a non-loopback interface instead of always showing 127.0.0.1/localhost. - setup.sh: Use run_quiet_no_exit instead of run_quiet_no_exit_always for npm install steps so --verbose correctly surfaces npm output. * Fix install.ps1 verbose stderr, propagate UNSLOTH_VERBOSE, fix git clone verbose - install.ps1: Apply same Invoke-InstallCommand fix as setup.ps1 -- merge stderr into stdout with 2>&1 and drop the $? check that misclassifies successful native commands on PS 5.1. - install.ps1 + setup.ps1: Export UNSLOTH_VERBOSE=1 to the process env when --verbose is passed so child processes like install_python_stack.py also run in verbose mode. - setup.sh: Use run_quiet_no_exit for git clone llama.cpp so --verbose correctly surfaces clone diagnostics during source-build fallback. * Surface prebuilt llama.cpp output in verbose mode, remove dead code, fix banner - setup.sh: Use tee in verbose mode for prebuilt llama.cpp installer so users can see download/validation progress while still capturing the log for structured error reporting on failure. - setup.ps1: Same fix for Windows -- use Tee-Object in verbose mode. - setup.sh: Remove run_quiet_no_exit_always() which has no remaining callers. - startup_banner.py: Avoid printing the same URL twice when Studio is bound to a specific non-loopback address that matches the display host. * Fix run_install_cmd exit code after failed if-statement The previous pattern 'if "$@"; then return 0; fi; _rc=$?' always captured $? = 0 because $? reflects the if-statement result, not the command's exit code. Switch to '"$@" && return 0; _rc=$?' which preserves the actual command exit code on failure. Applies to both verbose and quiet branches. * Fix _run_quiet exit code, double uv install, missing --local flag - setup.sh: Fix _run_quiet verbose path that always captured exit code 0 due to $? resetting after if-then-fi with no else. Switch to the same '"$@" && return 0; exit_code=$?' pattern used in install.sh. - setup.sh: Consolidate the two uv install branches (verbose + quiet) into a single attempt with conditional output. Previously, when verbose mode was on and the install failed, a second silent attempt was made. - install.ps1: Pass --local flag to 'unsloth studio update' when $StudioLocalInstall is true. Without this, studio.py's update() command overwrites STUDIO_LOCAL_INSTALL to "0", which could cause issues if setup.ps1 or install_python_stack.py later checks that variable. * Revert SKIP_STUDIO_BASE change for --no-torch, restore install banners - Revert SKIP_STUDIO_BASE from 0 to 1 for --no-torch. install.sh already installs unsloth+unsloth-zoo and no-torch-runtime.txt before calling setup.sh, so letting install_python_stack.py redo it was redundant and slowed down --no-torch installs for no benefit. - Restore the "Unsloth Studio installed!" success banner and "starting Unsloth Studio..." launch message so users get clear install completion feedback before the server starts. * Make llama.cpp build failure a hard error with proper cleanup - setup.sh: Restore exit 1 when _LLAMA_CPP_DEGRADED is true. GGUF inference requires a working llama.cpp build, so this should be a hard failure, not a silent degradation. - install.sh: Catch setup.sh's non-zero exit with '|| _SETUP_EXIT=$?' instead of letting set -e abort immediately. This ensures PATH setup, symlinks, and shortcuts still get created so the user can fix the build deps and retry with 'unsloth studio update'. After post-install steps, propagate the failure with a clear error message. * Revert install.ps1 to 'studio setup' to preserve SKIP_STUDIO_BASE 'studio update' pops SKIP_STUDIO_BASE from the environment, which defeats the fast-path version check added in PR unslothai#4667. When called from install.ps1 (which already installed packages), SKIP_STUDIO_BASE=1 must survive into setup.ps1 so it skips the redundant PyPI check and package reinstallation. 'studio setup' does not modify env vars. * Remove deprecation message from 'studio setup' command install.ps1 uses 'studio setup' (not 'studio update') to preserve SKIP_STUDIO_BASE. The deprecation message was confusing during first install since the user never typed the command. * Fix stale env vars, scope degraded exit, generic error message for PR unslothai#4651 - install.ps1: Always set STUDIO_LOCAL_INSTALL and clear STUDIO_LOCAL_REPO when not using --local, to prevent stale values from a previous --local run in the same PowerShell session. Fix log messages to say 'setup' not 'update' since we call 'studio setup'. - setup.sh: Only exit non-zero for degraded llama.cpp when called from the installer (SKIP_STUDIO_BASE=1). Direct 'unsloth studio update' keeps degraded installs successful since Studio is still usable for non-GGUF workflows and the footer already reports the limitation. - install.sh: Make the setup failure error message generic instead of GGUF-specific, so unrelated failures (npm, Python deps) do not show misleading cmake/git recovery advice. * Show captured output on failure in quiet mode for PR unslothai#4651 Both Invoke-InstallCommand (install.ps1) and Invoke-SetupCommand (setup.ps1) now capture command output in quiet mode and display it in red when the command fails. This matches the behavior of run_install_cmd in install.sh where failure output is surfaced even in quiet mode, making cross-platform error debugging consistent. * Match degraded llama.cpp exit on Windows, fix --local recovery hint for PR unslothai#4651 - setup.ps1: Exit non-zero for degraded llama.cpp when called from install.ps1 (SKIP_STUDIO_BASE=1), matching setup.sh behavior. Direct 'unsloth studio update' keeps degraded installs successful. - install.sh: Show 'unsloth studio update --local' in the recovery message when the install was run with --local, so users retry with the correct flag instead of losing local checkout context. --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Daniel Han <danielhanchen@gmail.com>
Standardizes Studio setup/install UX and logging behavior across Windows + shell scripts, while preserving newer upstream functionality merged from
main(including no-torch install support).install.ps1output style with Studio setup style:setup.ps1palette.step/substepformatting.--verbose/-v/UNSLOTH_VERBOSE=1preserves full command output.[ERROR] ... (exit code N)messages by default.:8888.upstream/maininto branch and resolved conflicts by preserving:--no-torch, no-torch runtime deps path),