From e510f3507a8522acd9a94aba5e8db7d04ce9e985 Mon Sep 17 00:00:00 2001 From: Mike Sawka Date: Mon, 20 Oct 2025 22:10:57 -0700 Subject: [PATCH] v0.12.1 release notes and onboarding (#2465) --- docs/docs/releasenotes.mdx | 20 ++ frontend/app/modals/about.tsx | 2 +- frontend/app/modals/modalsrenderer.tsx | 4 +- frontend/app/onboarding/onboarding-common.tsx | 4 + .../app/onboarding/onboarding-features.tsx | 3 +- .../onboarding/onboarding-upgrade-v0120.tsx | 201 ++++++++++++++++++ .../onboarding/onboarding-upgrade-v0121.tsx | 170 +++++++++++++++ .../app/onboarding/onboarding-upgrade.tsx | 186 ++-------------- frontend/app/view/preview/preview-model.tsx | 13 +- 9 files changed, 431 insertions(+), 172 deletions(-) create mode 100644 frontend/app/onboarding/onboarding-common.tsx create mode 100644 frontend/app/onboarding/onboarding-upgrade-v0120.tsx create mode 100644 frontend/app/onboarding/onboarding-upgrade-v0121.tsx diff --git a/docs/docs/releasenotes.mdx b/docs/docs/releasenotes.mdx index 402e28162..430a0394a 100644 --- a/docs/docs/releasenotes.mdx +++ b/docs/docs/releasenotes.mdx @@ -6,6 +6,26 @@ sidebar_position: 200 # Release Notes +### v0.12.1 — Oct 20, 2025 + +Patch release focused on shell integration improvements and Wave AI enhancements. This release fixes syntax highlighting in the code editor and adds significant shell context tracking capabilities. + +**Shell Integration & Context:** +- **OSC 7 Support** - Added OSC 7 (current working directory) support across bash, zsh, fish, and pwsh shells. Wave now automatically tracks and restores your current directory across restarts for both local and remote terminals. +- **Shell Context Tracking** - Implemented shell integration for bash, zsh, and fish shells. Wave now tracks when your shell is ready to receive commands, the last command executed, and exit codes. This enhanced context enables better terminal management and lays the groundwork for Wave AI to write and execute commands intelligently. + +**Wave AI Improvements:** +- Display reasoning summaries in the UI while waiting for AI responses +- Added enhanced terminal context - Wave AI now has access to shell state including current directory, command history, and exit codes +- Added feedback buttons (thumbs up/down) for AI responses to help improve the experience +- Added copy button to easily copy AI responses to clipboard + +**Other Changes:** +- Mobile user agent emulation support for web widgets [#2442](https://github.com/wavetermdev/waveterm/issues/2442) +- [bugfix] Fixed padding for header buttons in code editor (Tailwind regression) +- [bugfix] Restored syntax highlighting in code editor preview blocks [#2427](https://github.com/wavetermdev/waveterm/issues/2427) +- Package updates and dependency bumps + ### v0.12.0 — Oct 16, 2025 **Wave v0.12 Has Arrived with Wave AI (beta)!** diff --git a/frontend/app/modals/about.tsx b/frontend/app/modals/about.tsx index 739efc5e4..b448e4bbe 100644 --- a/frontend/app/modals/about.tsx +++ b/frontend/app/modals/about.tsx @@ -17,7 +17,7 @@ const AboutModal = ({}: AboutModalProps) => { const [updaterChannel] = useState(() => getApi().getUpdaterChannel()); return ( - modalsModel.popModal()}> + modalsModel.popModal()}>
diff --git a/frontend/app/modals/modalsrenderer.tsx b/frontend/app/modals/modalsrenderer.tsx index e8a95ea92..8576fb3be 100644 --- a/frontend/app/modals/modalsrenderer.tsx +++ b/frontend/app/modals/modalsrenderer.tsx @@ -2,13 +2,13 @@ // SPDX-License-Identifier: Apache-2.0 import { NewInstallOnboardingModal } from "@/app/onboarding/onboarding"; -import { CurrentOnboardingVersion } from "@/app/onboarding/onboarding-features"; +import { CurrentOnboardingVersion } from "@/app/onboarding/onboarding-common"; import { UpgradeOnboardingModal } from "@/app/onboarding/onboarding-upgrade"; import { atoms, globalPrimaryTabStartup, globalStore } from "@/store/global"; import { modalsModel } from "@/store/modalmodel"; import * as jotai from "jotai"; import { useEffect } from "react"; -import semver from "semver"; +import * as semver from "semver"; import { getModalComponent } from "./modalregistry"; const ModalsRenderer = () => { diff --git a/frontend/app/onboarding/onboarding-common.tsx b/frontend/app/onboarding/onboarding-common.tsx new file mode 100644 index 000000000..80cec552c --- /dev/null +++ b/frontend/app/onboarding/onboarding-common.tsx @@ -0,0 +1,4 @@ +// Copyright 2025, Command Line Inc. +// SPDX-License-Identifier: Apache-2.0 + +export const CurrentOnboardingVersion = "v0.12.1"; diff --git a/frontend/app/onboarding/onboarding-features.tsx b/frontend/app/onboarding/onboarding-features.tsx index 2b88f7cb4..b5f1706c4 100644 --- a/frontend/app/onboarding/onboarding-features.tsx +++ b/frontend/app/onboarding/onboarding-features.tsx @@ -12,11 +12,10 @@ import { TabRpcClient } from "@/app/store/wshrpcutil"; import { isMacOS } from "@/util/platformutil"; import { useEffect, useState } from "react"; import { FakeChat } from "./fakechat"; +import { CurrentOnboardingVersion } from "./onboarding-common"; import { EditBashrcCommand, ViewLogoCommand, ViewShortcutsCommand } from "./onboarding-command"; import { FakeLayout } from "./onboarding-layout"; -export const CurrentOnboardingVersion = "v0.12.0"; - type FeaturePageName = "waveai" | "magnify" | "files"; const OnboardingFooter = ({ diff --git a/frontend/app/onboarding/onboarding-upgrade-v0120.tsx b/frontend/app/onboarding/onboarding-upgrade-v0120.tsx new file mode 100644 index 000000000..2e1fe52ca --- /dev/null +++ b/frontend/app/onboarding/onboarding-upgrade-v0120.tsx @@ -0,0 +1,201 @@ +// Copyright 2025, Command Line Inc. +// SPDX-License-Identifier: Apache-2.0 + +import Logo from "@/app/asset/logo.svg"; +import { Button } from "@/app/element/button"; +import { FlexiModal } from "@/app/modals/modal"; +import { CurrentOnboardingVersion } from "@/app/onboarding/onboarding-common"; +import { OnboardingFeatures } from "@/app/onboarding/onboarding-features"; +import { atoms, globalStore } from "@/app/store/global"; +import { disableGlobalKeybindings, enableGlobalKeybindings, globalRefocus } from "@/app/store/keymodel"; +import { modalsModel } from "@/app/store/modalmodel"; +import * as WOS from "@/app/store/wos"; +import { RpcApi } from "@/app/store/wshclientapi"; +import { TabRpcClient } from "@/app/store/wshrpcutil"; +import { OverlayScrollbarsComponent } from "overlayscrollbars-react"; +import { useEffect, useRef, useState } from "react"; +import { debounce } from "throttle-debounce"; + +const UpgradeOnboardingModal_v0_12_0 = () => { + const modalRef = useRef(null); + const [pageName, setPageName] = useState<"welcome" | "features">("welcome"); + const [isCompact, setIsCompact] = useState(window.innerHeight < 800); + + const updateModalHeight = () => { + const windowHeight = window.innerHeight; + setIsCompact(windowHeight < 800); + if (modalRef.current) { + const modalHeight = modalRef.current.offsetHeight; + const maxHeight = windowHeight * 0.9; + if (maxHeight < modalHeight) { + modalRef.current.style.height = `${maxHeight}px`; + } else { + modalRef.current.style.height = "auto"; + } + } + }; + + useEffect(() => { + updateModalHeight(); + const debouncedUpdateModalHeight = debounce(150, updateModalHeight); + window.addEventListener("resize", debouncedUpdateModalHeight); + return () => { + window.removeEventListener("resize", debouncedUpdateModalHeight); + }; + }, []); + + useEffect(() => { + disableGlobalKeybindings(); + return () => { + enableGlobalKeybindings(); + }; + }, []); + + const handleStarClick = async () => { + RpcApi.RecordTEventCommand( + TabRpcClient, + { + event: "onboarding:githubstar", + props: { "onboarding:githubstar": "star" }, + }, + { noresponse: true } + ); + const clientId = globalStore.get(atoms.clientId); + await RpcApi.SetMetaCommand(TabRpcClient, { + oref: WOS.makeORef("client", clientId), + meta: { "onboarding:githubstar": true }, + }); + window.open("https://github.com/wavetermdev/waveterm?ref=upgrade", "_blank"); + setPageName("features"); + }; + + const handleAlreadyStarred = async () => { + RpcApi.RecordTEventCommand( + TabRpcClient, + { + event: "onboarding:githubstar", + props: { "onboarding:githubstar": "already" }, + }, + { noresponse: true } + ); + const clientId = globalStore.get(atoms.clientId); + await RpcApi.SetMetaCommand(TabRpcClient, { + oref: WOS.makeORef("client", clientId), + meta: { "onboarding:githubstar": true }, + }); + setPageName("features"); + }; + + const handleMaybeLater = async () => { + RpcApi.RecordTEventCommand( + TabRpcClient, + { + event: "onboarding:githubstar", + props: { "onboarding:githubstar": "later" }, + }, + { noresponse: true } + ); + const clientId = globalStore.get(atoms.clientId); + await RpcApi.SetMetaCommand(TabRpcClient, { + oref: WOS.makeORef("client", clientId), + meta: { "onboarding:githubstar": false }, + }); + setPageName("features"); + }; + + const handleFeaturesComplete = () => { + const clientId = globalStore.get(atoms.clientId); + RpcApi.SetMetaCommand(TabRpcClient, { + oref: WOS.makeORef("client", clientId), + meta: { "onboarding:lastversion": CurrentOnboardingVersion }, + }); + globalStore.set(modalsModel.upgradeOnboardingOpen, false); + setTimeout(() => { + globalRefocus(); + }, 10); + }; + + let pageComp: React.JSX.Element = null; + if (pageName === "welcome") { + pageComp = ( +
+
+
+ +
+
Welcome to Wave v0.12!
+
+ +
+
+
+ + Wave AI +
+
+

+ Wave AI is your new terminal assistant with full context. It can read your terminal + output, analyze widgets, access files, and help you solve problems faster. +

+

+ Wave AI is in active beta with included AI credits while we refine the experience. + We're actively improving it and would love your feedback in{" "} + + Discord + + . +

+
+
+ +
+ +
+
Thanks for being an early Wave adopter! ⭐
+
+ A GitHub star shows your support for Wave (and open-source) and helps us reach more + developers. +
+
+
+
+
+
+ + + +
+
+
+ ); + } else if (pageName === "features") { + pageComp = ; + } + + if (pageComp == null) { + return null; + } + + const paddingClass = isCompact ? "!py-3 !px-[30px]" : "!p-[30px]"; + const widthClass = pageName === "features" ? "w-[800px]" : "w-[560px]"; + + return ( + +
+
{pageComp}
+ + ); +}; + +UpgradeOnboardingModal_v0_12_0.displayName = "UpgradeOnboardingModal_v0_12_0"; + +export { UpgradeOnboardingModal_v0_12_0 }; \ No newline at end of file diff --git a/frontend/app/onboarding/onboarding-upgrade-v0121.tsx b/frontend/app/onboarding/onboarding-upgrade-v0121.tsx new file mode 100644 index 000000000..051b623cb --- /dev/null +++ b/frontend/app/onboarding/onboarding-upgrade-v0121.tsx @@ -0,0 +1,170 @@ +// Copyright 2025, Command Line Inc. +// SPDX-License-Identifier: Apache-2.0 + +import Logo from "@/app/asset/logo.svg"; +import { Button } from "@/app/element/button"; +import { FlexiModal } from "@/app/modals/modal"; +import { CurrentOnboardingVersion } from "@/app/onboarding/onboarding-common"; +import { atoms, globalStore } from "@/app/store/global"; +import { disableGlobalKeybindings, enableGlobalKeybindings, globalRefocus } from "@/app/store/keymodel"; +import { modalsModel } from "@/app/store/modalmodel"; +import * as WOS from "@/app/store/wos"; +import { RpcApi } from "@/app/store/wshclientapi"; +import { TabRpcClient } from "@/app/store/wshrpcutil"; +import { OverlayScrollbarsComponent } from "overlayscrollbars-react"; +import { useEffect, useRef, useState } from "react"; +import { debounce } from "throttle-debounce"; + +const UpgradeOnboardingModal_v0_12_1 = () => { + const modalRef = useRef(null); + const [isCompact, setIsCompact] = useState(window.innerHeight < 800); + + const updateModalHeight = () => { + const windowHeight = window.innerHeight; + setIsCompact(windowHeight < 800); + if (modalRef.current) { + const modalHeight = modalRef.current.offsetHeight; + const maxHeight = windowHeight * 0.9; + if (maxHeight < modalHeight) { + modalRef.current.style.height = `${maxHeight}px`; + } else { + modalRef.current.style.height = "auto"; + } + } + }; + + useEffect(() => { + updateModalHeight(); + const debouncedUpdateModalHeight = debounce(150, updateModalHeight); + window.addEventListener("resize", debouncedUpdateModalHeight); + return () => { + window.removeEventListener("resize", debouncedUpdateModalHeight); + }; + }, []); + + useEffect(() => { + disableGlobalKeybindings(); + return () => { + enableGlobalKeybindings(); + }; + }, []); + + const handleClose = () => { + const clientId = globalStore.get(atoms.clientId); + RpcApi.SetMetaCommand(TabRpcClient, { + oref: WOS.makeORef("client", clientId), + meta: { "onboarding:lastversion": CurrentOnboardingVersion }, + }); + globalStore.set(modalsModel.upgradeOnboardingOpen, false); + setTimeout(() => { + globalRefocus(); + }, 10); + }; + + const paddingClass = isCompact ? "!py-3 !px-[30px]" : "!p-[30px]"; + + return ( + +
+
+
+
+
+ +
+
Wave v0.12.1 Update
+
+ +
+
+

+ Patch release focused on shell integration improvements, Wave AI enhancements, and + restoring syntax highlighting in code editor blocks. +

+
+ +
+
+ +
+
+
+ Shell Integration & Context +
+
+
    +
  • + OSC 7 Support - Wave now automatically tracks and + restores your current directory across restarts for bash, zsh, fish, and + pwsh shells +
  • +
  • + Shell Context Tracking - Tracks when your shell is + ready, last command executed, and exit codes for better terminal + management +
  • +
+
+
+
+ +
+
+ +
+
+
+ Wave AI Improvements +
+
+
    +
  • Display reasoning summaries while waiting for AI responses
  • +
  • + Enhanced terminal context - AI now has access to shell state, current + directory, command history, and exit codes +
  • +
  • Added feedback buttons (thumbs up/down) for AI responses
  • +
  • Added copy button to easily copy AI responses to clipboard
  • +
+
+
+
+ +
+
+ +
+
+
+ Other Changes +
+
+
    +
  • Mobile user agent emulation support for web widgets
  • +
  • Fixed padding for header buttons in code editor
  • +
  • Restored syntax highlighting in code editor preview blocks
  • +
+
+
+
+
+
+
+
+ +
+
+
+
+ + ); +}; + +UpgradeOnboardingModal_v0_12_1.displayName = "UpgradeOnboardingModal_v0_12_1"; + +export { UpgradeOnboardingModal_v0_12_1 }; diff --git a/frontend/app/onboarding/onboarding-upgrade.tsx b/frontend/app/onboarding/onboarding-upgrade.tsx index 2de94f1e7..c2c7a9853 100644 --- a/frontend/app/onboarding/onboarding-upgrade.tsx +++ b/frontend/app/onboarding/onboarding-upgrade.tsx @@ -1,181 +1,39 @@ // Copyright 2025, Command Line Inc. // SPDX-License-Identifier: Apache-2.0 -import Logo from "@/app/asset/logo.svg"; -import { Button } from "@/app/element/button"; -import { FlexiModal } from "@/app/modals/modal"; -import { OnboardingFeatures } from "@/app/onboarding/onboarding-features"; import { atoms, globalStore } from "@/app/store/global"; -import { disableGlobalKeybindings, enableGlobalKeybindings, globalRefocus } from "@/app/store/keymodel"; import { modalsModel } from "@/app/store/modalmodel"; -import * as WOS from "@/app/store/wos"; -import { RpcApi } from "@/app/store/wshclientapi"; -import { TabRpcClient } from "@/app/store/wshrpcutil"; -import { OverlayScrollbarsComponent } from "overlayscrollbars-react"; -import { useEffect, useRef, useState } from "react"; -import { debounce } from "throttle-debounce"; +import { useAtomValue } from "jotai"; +import { useEffect, useRef } from "react"; +import * as semver from "semver"; +import { UpgradeOnboardingModal_v0_12_0 } from "./onboarding-upgrade-v0120"; +import { UpgradeOnboardingModal_v0_12_1 } from "./onboarding-upgrade-v0121"; const UpgradeOnboardingModal = () => { - const modalRef = useRef(null); - const [pageName, setPageName] = useState<"welcome" | "features">("welcome"); - const [isCompact, setIsCompact] = useState(window.innerHeight < 800); + const clientData = useAtomValue(atoms.client); + const initialVersionRef = useRef(null); - const updateModalHeight = () => { - const windowHeight = window.innerHeight; - setIsCompact(windowHeight < 800); - if (modalRef.current) { - const modalHeight = modalRef.current.offsetHeight; - const maxHeight = windowHeight * 0.9; - if (maxHeight < modalHeight) { - modalRef.current.style.height = `${maxHeight}px`; - } else { - modalRef.current.style.height = "auto"; - } - } - }; - - useEffect(() => { - updateModalHeight(); - const debouncedUpdateModalHeight = debounce(150, updateModalHeight); - window.addEventListener("resize", debouncedUpdateModalHeight); - return () => { - window.removeEventListener("resize", debouncedUpdateModalHeight); - }; - }, []); - - useEffect(() => { - disableGlobalKeybindings(); - return () => { - enableGlobalKeybindings(); - }; - }, []); - - const handleStarClick = async () => { - RpcApi.RecordTEventCommand(TabRpcClient, { - event: "onboarding:githubstar", - props: { "onboarding:githubstar": "star" }, - }, { noresponse: true }); - const clientId = globalStore.get(atoms.clientId); - await RpcApi.SetMetaCommand(TabRpcClient, { - oref: WOS.makeORef("client", clientId), - meta: { "onboarding:githubstar": true }, - }); - window.open("https://github.com/wavetermdev/waveterm?ref=upgrade", "_blank"); - setPageName("features"); - }; - - const handleAlreadyStarred = async () => { - RpcApi.RecordTEventCommand(TabRpcClient, { - event: "onboarding:githubstar", - props: { "onboarding:githubstar": "already" }, - }, { noresponse: true }); - const clientId = globalStore.get(atoms.clientId); - await RpcApi.SetMetaCommand(TabRpcClient, { - oref: WOS.makeORef("client", clientId), - meta: { "onboarding:githubstar": true }, - }); - setPageName("features"); - }; - - const handleMaybeLater = async () => { - RpcApi.RecordTEventCommand(TabRpcClient, { - event: "onboarding:githubstar", - props: { "onboarding:githubstar": "later" }, - }, { noresponse: true }); - const clientId = globalStore.get(atoms.clientId); - await RpcApi.SetMetaCommand(TabRpcClient, { - oref: WOS.makeORef("client", clientId), - meta: { "onboarding:githubstar": false }, - }); - setPageName("features"); - }; - - const handleFeaturesComplete = () => { - globalStore.set(modalsModel.upgradeOnboardingOpen, false); - setTimeout(() => { - globalRefocus(); - }, 10); - }; - - let pageComp: React.JSX.Element = null; - if (pageName === "welcome") { - pageComp = ( -
-
-
- -
-
Welcome to Wave v0.12!
-
- -
-
-
- - Wave AI -
-
-

- Wave AI is your new terminal assistant with full context. It can read your terminal - output, analyze widgets, access files, and help you solve problems faster. -

-

- Wave AI is in active beta with included AI credits while we refine the experience. - We're actively improving it and would love your feedback in{" "} - - Discord - - . -

-
-
- -
- -
-
Thanks for being an early Wave adopter! ⭐
-
- A GitHub star shows your support for Wave (and open-source) and helps us reach more - developers. -
-
-
-
-
-
- - - -
-
-
- ); - } else if (pageName === "features") { - pageComp = ; + if (initialVersionRef.current == null) { + initialVersionRef.current = clientData.meta?.["onboarding:lastversion"] ?? "v0.0.0"; } - if (pageComp == null) { + const lastVersion = initialVersionRef.current; + + useEffect(() => { + if (semver.gte(lastVersion, "v0.12.1")) { + globalStore.set(modalsModel.upgradeOnboardingOpen, false); + } + }, [lastVersion]); + + if (semver.gte(lastVersion, "v0.12.1")) { return null; } - const paddingClass = isCompact ? "!py-3 !px-[30px]" : "!p-[30px]"; - const widthClass = pageName === "features" ? "w-[800px]" : "w-[560px]"; + if (semver.gte(lastVersion, "v0.12.0")) { + return ; + } - return ( - -
-
{pageComp}
- - ); + return ; }; UpgradeOnboardingModal.displayName = "UpgradeOnboardingModal"; diff --git a/frontend/app/view/preview/preview-model.tsx b/frontend/app/view/preview/preview-model.tsx index 2c53cd11c..2ab8f0b29 100644 --- a/frontend/app/view/preview/preview-model.tsx +++ b/frontend/app/view/preview/preview-model.tsx @@ -79,6 +79,13 @@ function isStreamingType(mimeType: string): boolean { ); } +function isMarkdownLike(mimeType: string): boolean { + if (mimeType == null) { + return false; + } + return mimeType.startsWith("text/markdown") || mimeType.startsWith("text/mdx"); +} + function iconForFile(mimeType: string): string { if (mimeType == null) { mimeType = "unknown"; @@ -91,7 +98,7 @@ function iconForFile(mimeType: string): string { return "film"; } else if (mimeType.startsWith("audio/")) { return "headphones"; - } else if (mimeType.startsWith("text/markdown")) { + } else if (isMarkdownLike(mimeType)) { return "file-lines"; } else if (mimeType == "text/csv") { return "file-csv"; @@ -333,7 +340,7 @@ export class PreviewModel implements ViewModel { click: () => this.refreshCallback?.(), }, ] as IconButtonDecl[]; - } else if (!isCeView && mimeType?.startsWith("text/markdown")) { + } else if (!isCeView && isMarkdownLike(mimeType)) { return [ { elemtype: "iconbutton", @@ -508,7 +515,7 @@ export class PreviewModel implements ViewModel { } return { specializedView: "csv" }; } - if (mimeType.startsWith("text/markdown")) { + if (isMarkdownLike(mimeType)) { if (editMode) { return { specializedView: "codeedit" }; }