Studio: copy the OS-matched update command and keep checkout installs local

The web update banner copied both the macOS/Linux curl and the Windows irm
one-liner joined by a newline, so pasting into a single terminal ran the wrong
shell's command and errored. Detect the OS from navigator.userAgent and copy
only the matching command; the banner still displays both.

In the settings update panel, editable/local_repo checkouts were told to run
the remote curl/irm installer, which is the PyPI path (install.sh only installs
locally with --local) and would replace an editable checkout with a PyPI
package. Use the OS-specific local installer (./install.sh --local /
.\install.ps1 --local) as the checkout update command and drop the now
redundant duplicate block plus its unused localInstallerFallback locale key.
This commit is contained in:
Daniel Han 2026-06-14 12:21:13 +00:00
commit d75fa36832
4 changed files with 13 additions and 24 deletions

View file

@ -10,7 +10,9 @@ import { type ReactElement, useEffect, useRef, useState } from "react";
const STUDIO_UPDATE_UNIX_CMD = "curl -fsSL https://unsloth.ai/install.sh | sh";
const STUDIO_UPDATE_WINDOWS_CMD = "irm https://unsloth.ai/install.ps1 | iex";
const STUDIO_UPDATE_COPY_CMD = `${STUDIO_UPDATE_UNIX_CMD}\n${STUDIO_UPDATE_WINDOWS_CMD}`;
// Match "windows" (every Windows UA carries "Windows NT") rather than "win",
// which also matches "Darwin" and would mis-detect macOS as Windows.
const WINDOWS_UA_RE = /windows/i;
const RELEASE_NOTES_URL = "https://unsloth.ai/docs/new/changelog";
const EASE_OUT_QUART: [number, number, number, number] = [0.165, 0.84, 0.44, 1];
@ -38,7 +40,15 @@ export function WebUpdateBanner({
}
async function handleCopyCommand() {
if (!(await copyToClipboard(STUDIO_UPDATE_COPY_CMD))) {
// Copy only the command for the user's OS: pasting both (Unix + PowerShell)
// into a single terminal runs the wrong one and errors out.
const isWindows =
typeof navigator !== "undefined" &&
WINDOWS_UA_RE.test(navigator.userAgent || "");
const command = isWindows
? STUDIO_UPDATE_WINDOWS_CMD
: STUDIO_UPDATE_UNIX_CMD;
if (!(await copyToClipboard(command))) {
return;
}
setCopiedVersion(status?.latestVersion ?? null);

View file

@ -230,23 +230,6 @@ export function UpdateStudioInstructions({
animate={fadeAnimate}
exit={fadeExit}
transition={fadeTransition}
>
<CopyableCommand
command={updateCmd}
copyLabel={t("settings.about.update.localUpdateCommand")}
/>
</motion.div>
</AnimatePresence>
<p className="text-xs text-muted-foreground leading-relaxed">
{t("settings.about.update.localInstallerFallback")}
</p>
<AnimatePresence mode="wait" initial={false}>
<motion.div
key={`local-fallback-${shell}`}
initial={fadeInitial}
animate={fadeAnimate}
exit={fadeExit}
transition={fadeTransition}
>
<CopyableCommand
command={
@ -254,7 +237,7 @@ export function UpdateStudioInstructions({
? STUDIO_LOCAL_FALLBACK_WINDOWS_CMD
: STUDIO_LOCAL_FALLBACK_UNIX_CMD
}
copyLabel={t("settings.about.update.localInstallerCommand")}
copyLabel={t("settings.about.update.localUpdateCommand")}
/>
</motion.div>
</AnimatePresence>

View file

@ -307,8 +307,6 @@ export const en = {
"Pull latest changes from your Unsloth repo checkout, then update Studio locally:",
gitPullCommand: "git pull command",
localUpdateCommand: "local update command",
localInstallerFallback:
"If the Studio update command is unavailable, run the local installer from that checkout:",
localInstallerCommand: "local installer command",
sourceInstallDetected:
"This looks like a source or VCS package install. Reinstall from the original local path or Git URL you used.",

View file

@ -288,8 +288,6 @@ export const zhCN = {
"从你的 Unsloth 仓库 checkout 拉取最新变更,然后本地更新 Studio",
gitPullCommand: "git pull 命令",
localUpdateCommand: "本地更新命令",
localInstallerFallback:
"如果 Studio 更新命令不可用,请从该 checkout 运行本地安装器:",
localInstallerCommand: "本地安装器命令",
sourceInstallDetected:
"这看起来是源码或 VCS 包安装。请从最初使用的本地路径或 Git URL 重新安装。",