Compare commits
2 commits
main
...
studio-upd
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d75fa36832 | ||
|
|
84cf03c015 |
11 changed files with 72 additions and 70 deletions
|
|
@ -3651,8 +3651,9 @@ class LlamaCppBackend:
|
|||
logger.warning(
|
||||
"Requested MTP speculative decoding but "
|
||||
"llama-server lacks --spec-type mtp/draft-mtp; "
|
||||
"run `unsloth studio update`. Loading without "
|
||||
"speculative decoding."
|
||||
"update by running curl -fsSL https://unsloth.ai/install.sh | sh "
|
||||
"(macOS/Linux) or irm https://unsloth.ai/install.ps1 | iex "
|
||||
"(Windows). Loading without speculative decoding."
|
||||
)
|
||||
return False
|
||||
draft_n_max = _resolved_draft_n_max()
|
||||
|
|
|
|||
|
|
@ -344,7 +344,9 @@ async def lifespan(app: FastAPI):
|
|||
if _caps.get("found") and not _caps.get("supports_mtp"):
|
||||
_msg = (
|
||||
"llama.cpp prebuilt lacks MTP support "
|
||||
"(--spec-type mtp/draft-mtp). Run `unsloth studio update`. "
|
||||
"(--spec-type mtp/draft-mtp). Update by running "
|
||||
"curl -fsSL https://unsloth.ai/install.sh | sh (macOS/Linux) or "
|
||||
"irm https://unsloth.ai/install.ps1 | iex (Windows). "
|
||||
"MTP GGUFs will load without speculative decoding."
|
||||
)
|
||||
_log.warning(_msg)
|
||||
|
|
|
|||
|
|
@ -317,7 +317,8 @@ def test_format_stale_warning_contains_actionable_command():
|
|||
assert "b9190" in msg
|
||||
assert "b9300" in msg
|
||||
assert "5 days" in msg
|
||||
assert "unsloth studio update" in msg
|
||||
assert "install.sh" in msg
|
||||
assert "install.ps1" in msg
|
||||
|
||||
|
||||
def test_format_stale_warning_singular_day():
|
||||
|
|
|
|||
|
|
@ -233,8 +233,9 @@ def format_stale_warning(info: dict) -> str:
|
|||
age_str = f"{age} day{'s' if age != 1 else ''}" if age is not None else "some time"
|
||||
return (
|
||||
f"llama.cpp prebuilt is {age_str} behind: installed "
|
||||
f"{installed}, latest {latest}. Run `unsloth studio update` "
|
||||
f"to refresh."
|
||||
f"{installed}, latest {latest}. Update to refresh by running "
|
||||
f"curl -fsSL https://unsloth.ai/install.sh | sh (macOS/Linux) or "
|
||||
f"irm https://unsloth.ai/install.ps1 | iex (Windows)."
|
||||
)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -102,7 +102,7 @@ export function UpdateBanner({
|
|||
: isManualLinuxPackage
|
||||
? "Open the GitHub release page to install the Linux package"
|
||||
: isExternalServer
|
||||
? "Run `unsloth studio update` from your terminal"
|
||||
? "To update, run curl -fsSL https://unsloth.ai/install.sh | sh (macOS/Linux) or irm https://unsloth.ai/install.ps1 | iex (Windows) from your terminal"
|
||||
: "A new app update is available"}
|
||||
</p>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -8,7 +8,11 @@ import { copyToClipboard } from "@/lib/copy-to-clipboard";
|
|||
import { AnimatePresence, motion } from "motion/react";
|
||||
import { type ReactElement, useEffect, useRef, useState } from "react";
|
||||
|
||||
const STUDIO_UPDATE_CMD = "unsloth studio update";
|
||||
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";
|
||||
// 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];
|
||||
|
||||
|
|
@ -36,7 +40,15 @@ export function WebUpdateBanner({
|
|||
}
|
||||
|
||||
async function handleCopyCommand() {
|
||||
if (!(await copyToClipboard(STUDIO_UPDATE_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);
|
||||
|
|
@ -90,8 +102,23 @@ export function WebUpdateBanner({
|
|||
</p>
|
||||
<p className="mt-1 text-xs leading-relaxed text-muted-foreground">
|
||||
Installed package: {status.currentVersion}. To update Studio,
|
||||
run this in your terminal, then restart Studio.
|
||||
run the command for your OS in a terminal, then restart
|
||||
Studio.
|
||||
</p>
|
||||
<div className="mt-2 space-y-1">
|
||||
<p className="text-[10px] font-medium uppercase tracking-wide text-muted-foreground/70">
|
||||
macOS / Linux
|
||||
</p>
|
||||
<code className="block overflow-x-auto rounded bg-muted/60 px-2 py-1 font-mono text-[11px] text-foreground">
|
||||
{STUDIO_UPDATE_UNIX_CMD}
|
||||
</code>
|
||||
<p className="text-[10px] font-medium uppercase tracking-wide text-muted-foreground/70">
|
||||
Windows (PowerShell)
|
||||
</p>
|
||||
<code className="block overflow-x-auto rounded bg-muted/60 px-2 py-1 font-mono text-[11px] text-foreground">
|
||||
{STUDIO_UPDATE_WINDOWS_CMD}
|
||||
</code>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
// Copyright 2026-present the Unsloth AI Inc. team. All rights reserved. See /studio/LICENSE.AGPL-3.0
|
||||
|
||||
import { copyToClipboard } from "@/lib/copy-to-clipboard";
|
||||
import { useT } from "@/i18n";
|
||||
import { copyToClipboard } from "@/lib/copy-to-clipboard";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { Copy01Icon, Tick02Icon } from "@hugeicons/core-free-icons";
|
||||
import { HugeiconsIcon } from "@hugeicons/react";
|
||||
|
|
@ -10,13 +10,9 @@ import { AnimatePresence, motion, useReducedMotion } from "motion/react";
|
|||
import type { ReactElement } from "react";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
|
||||
const STUDIO_UPDATE_CMD = "unsloth studio update";
|
||||
const STUDIO_UPDATE_FALLBACK_UNIX_CMD =
|
||||
"curl -fsSL https://unsloth.ai/install.sh | sh";
|
||||
const STUDIO_UPDATE_FALLBACK_WINDOWS_CMD =
|
||||
"irm https://unsloth.ai/install.ps1 | iex";
|
||||
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_LOCAL_PULL_CMD = "git pull --ff-only";
|
||||
const STUDIO_LOCAL_UPDATE_CMD = "unsloth studio update --local";
|
||||
const STUDIO_LOCAL_FALLBACK_UNIX_CMD = "./install.sh --local";
|
||||
const STUDIO_LOCAL_FALLBACK_WINDOWS_CMD = ".\\install.ps1 --local";
|
||||
|
||||
|
|
@ -145,6 +141,9 @@ export function UpdateStudioInstructions({
|
|||
const shell = shellOverride ?? defaultShell;
|
||||
const prefersReducedMotion = useReducedMotion();
|
||||
const windows = shell === "windows";
|
||||
const updateCmd = windows
|
||||
? STUDIO_UPDATE_WINDOWS_CMD
|
||||
: STUDIO_UPDATE_UNIX_CMD;
|
||||
const localInstallSource = isLocalInstallSource(installSource);
|
||||
const checkoutInstallSource =
|
||||
installSource === "editable" || installSource === "local_repo";
|
||||
|
|
@ -224,16 +223,9 @@ export function UpdateStudioInstructions({
|
|||
command={STUDIO_LOCAL_PULL_CMD}
|
||||
copyLabel={t("settings.about.update.gitPullCommand")}
|
||||
/>
|
||||
<CopyableCommand
|
||||
command={STUDIO_LOCAL_UPDATE_CMD}
|
||||
copyLabel={t("settings.about.update.localUpdateCommand")}
|
||||
/>
|
||||
<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}`}
|
||||
key={`local-update-${shell}`}
|
||||
initial={fadeInitial}
|
||||
animate={fadeAnimate}
|
||||
exit={fadeExit}
|
||||
|
|
@ -245,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>
|
||||
|
|
@ -291,17 +283,20 @@ export function UpdateStudioInstructions({
|
|||
<p className="text-xs text-muted-foreground leading-relaxed">
|
||||
{t("settings.about.update.curlOrPypi")}
|
||||
</p>
|
||||
<CopyableCommand
|
||||
command={STUDIO_UPDATE_CMD}
|
||||
copyLabel={t("settings.about.update.updateCommand")}
|
||||
/>
|
||||
<p className="text-xs text-muted-foreground leading-relaxed">
|
||||
{t("settings.about.update.localCheckout")}
|
||||
</p>
|
||||
<CopyableCommand
|
||||
command={STUDIO_LOCAL_UPDATE_CMD}
|
||||
copyLabel={t("settings.about.update.localUpdateCommand")}
|
||||
/>
|
||||
<AnimatePresence mode="wait" initial={false}>
|
||||
<motion.div
|
||||
key={`unknown-update-${shell}`}
|
||||
initial={fadeInitial}
|
||||
animate={fadeAnimate}
|
||||
exit={fadeExit}
|
||||
transition={fadeTransition}
|
||||
>
|
||||
<CopyableCommand
|
||||
command={updateCmd}
|
||||
copyLabel={t("settings.about.update.updateCommand")}
|
||||
/>
|
||||
</motion.div>
|
||||
</AnimatePresence>
|
||||
<p className="text-xs text-muted-foreground leading-relaxed">
|
||||
{t("settings.about.update.restartAfterUpdate")}
|
||||
</p>
|
||||
|
|
@ -320,28 +315,17 @@ export function UpdateStudioInstructions({
|
|||
{getStudioUpdateInstructionLine(shell, t)}
|
||||
</motion.p>
|
||||
</AnimatePresence>
|
||||
<CopyableCommand
|
||||
command={STUDIO_UPDATE_CMD}
|
||||
copyLabel={t("settings.about.update.updateCommand")}
|
||||
/>
|
||||
<p className="text-xs text-muted-foreground leading-relaxed">
|
||||
{t("settings.about.update.fallbackInstruction")}
|
||||
</p>
|
||||
<AnimatePresence mode="wait" initial={false}>
|
||||
<motion.div
|
||||
key={`fallback-${shell}`}
|
||||
key={`update-${shell}`}
|
||||
initial={fadeInitial}
|
||||
animate={fadeAnimate}
|
||||
exit={fadeExit}
|
||||
transition={fadeTransition}
|
||||
>
|
||||
<CopyableCommand
|
||||
command={
|
||||
windows
|
||||
? STUDIO_UPDATE_FALLBACK_WINDOWS_CMD
|
||||
: STUDIO_UPDATE_FALLBACK_UNIX_CMD
|
||||
}
|
||||
copyLabel={t("settings.about.update.fallbackCommand")}
|
||||
command={updateCmd}
|
||||
copyLabel={t("settings.about.update.updateCommand")}
|
||||
/>
|
||||
</motion.div>
|
||||
</AnimatePresence>
|
||||
|
|
|
|||
|
|
@ -71,8 +71,8 @@ function externalConflictMessage(preflight: DesktopPreflightResult) {
|
|||
}
|
||||
|
||||
return preflight.port
|
||||
? `A Studio server for this install is already running from a terminal on port ${preflight.port}. Stop that server, or run \`unsloth studio update\` from that terminal before using the desktop app.`
|
||||
: "A Studio server for this install is already running from a terminal. Stop that server, or run `unsloth studio update` from that terminal before using the desktop app.";
|
||||
? `A Studio server for this install is already running from a terminal on port ${preflight.port}. Stop that server, or update by running curl -fsSL https://unsloth.ai/install.sh | sh (macOS/Linux) or irm https://unsloth.ai/install.ps1 | iex (Windows) from that terminal before using the desktop app.`
|
||||
: "A Studio server for this install is already running from a terminal. Stop that server, or update by running curl -fsSL https://unsloth.ai/install.sh | sh (macOS/Linux) or irm https://unsloth.ai/install.ps1 | iex (Windows) from that terminal before using the desktop app.";
|
||||
}
|
||||
|
||||
async function waitForManagedServerReady(
|
||||
|
|
@ -248,8 +248,8 @@ export function useTauriBackend() {
|
|||
} else {
|
||||
setBackendError(
|
||||
preflight.disposition === "owned_stale"
|
||||
? "Desktop-owned Studio backend is too old for this desktop app. Run `unsloth studio update`, then restart Studio."
|
||||
: "Managed Studio install is too old. Run `unsloth studio update`.",
|
||||
? "Desktop-owned Studio backend is too old for this desktop app. Update by running curl -fsSL https://unsloth.ai/install.sh | sh (macOS/Linux) or irm https://unsloth.ai/install.ps1 | iex (Windows), then restart Studio."
|
||||
: "Managed Studio install is too old. Update by running curl -fsSL https://unsloth.ai/install.sh | sh (macOS/Linux) or irm https://unsloth.ai/install.ps1 | iex (Windows).",
|
||||
);
|
||||
}
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -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.",
|
||||
|
|
@ -320,11 +318,6 @@ export const en = {
|
|||
"Studio could not detect how it was installed. Check how you installed Studio first, then choose the matching update path.",
|
||||
curlOrPypi: "For curl or PyPI installs, run:",
|
||||
updateCommand: "update command",
|
||||
localCheckout:
|
||||
"For local checkout installs, update from that checkout instead and use the local update command:",
|
||||
fallbackInstruction:
|
||||
"If that fails or unsloth studio update is unavailable, run:",
|
||||
fallbackCommand: "fallback command",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -288,8 +288,6 @@ export const zhCN = {
|
|||
"从你的 Unsloth 仓库 checkout 拉取最新变更,然后本地更新 Studio:",
|
||||
gitPullCommand: "git pull 命令",
|
||||
localUpdateCommand: "本地更新命令",
|
||||
localInstallerFallback:
|
||||
"如果 Studio 更新命令不可用,请从该 checkout 运行本地安装器:",
|
||||
localInstallerCommand: "本地安装器命令",
|
||||
sourceInstallDetected:
|
||||
"这看起来是源码或 VCS 包安装。请从最初使用的本地路径或 Git URL 重新安装。",
|
||||
|
|
@ -300,11 +298,6 @@ export const zhCN = {
|
|||
"Studio 无法检测安装方式。请先确认你如何安装 Studio,然后选择匹配的更新方式。",
|
||||
curlOrPypi: "对于 curl 或 PyPI 安装,请运行:",
|
||||
updateCommand: "更新命令",
|
||||
localCheckout:
|
||||
"对于本地 checkout 安装,请改为从该 checkout 更新并使用本地更新命令:",
|
||||
fallbackInstruction:
|
||||
"如果失败,或 unsloth studio update 不可用,请运行:",
|
||||
fallbackCommand: "备用命令",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ fn external_conflict_message(conflict: &crate::preflight::ExternalBackendConflic
|
|||
);
|
||||
}
|
||||
format!(
|
||||
"A Studio server for this install is already running from a terminal on port {}. Stop that server, or run `unsloth studio update` from that terminal before using desktop repair/update.",
|
||||
"A Studio server for this install is already running from a terminal on port {}. Stop that server, or update by running curl -fsSL https://unsloth.ai/install.sh | sh (macOS/Linux) or irm https://unsloth.ai/install.ps1 | iex (Windows) from that terminal before using desktop repair/update.",
|
||||
conflict.port
|
||||
)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue