Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions docs/docs/releasenotes.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,26 @@ sidebar_position: 200

# Release Notes

### v0.12.2 — Nov 4, 2025

Wave v0.12.2 adds file editing ability to Wave AI. Before approving a file edit you can easily see a diff (rendered in the Monaco Editor diff viewer), and after approving an edit you can easily roll back the change using a "Revert File" button.

**Wave AI Updates:**
- **File Write Tool** - Wave AI can now create and modify files with your approval
- **Visual Diff Preview** - See exactly what will change before approving edits, rendered in Monaco Editor
- **Easy Rollback** - Revert file changes with a simple "Revert File" button
- **Drag & Drop Files** - Drag files from the preview viewer directly to Wave AI
- **Directory Listings** - `wsh ai` can now attach directory listings to chats
- **Adjustable Settings** - Control thinking level and max output tokens per chat

**Bug Fixes & Improvements:**
- Fixed a significant memory leak in the RPC system
- Schema validation working again for config files
- Improved tool descriptions and input validations (run before tool approvals)
- Fixed issue with premature tool timeouts
- Fixed regression with PowerShell 5.x
- Fixed prompt caching issue when attaching files

### 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.
Expand Down
19 changes: 19 additions & 0 deletions docs/docs/telemetry.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ Below is a list of the event types collected in the new telemetry system. More e
| `debug:panic` | Logged when a backend (Go) panic happens. Contains a debugging string that can be used to find which panic was hit in our source code. No data is sent |
| `conn:connect` | Logged each time a backend ssh/wsl connection connects (logs the conneciton type, no hostname or IP is sent) |
| `conn:connecterror` | Logged when you try to connect but it fails (logs the connection type, no hostname or IP is set, and no detailed error information is sent) |
| `waveai:post` | Logged after AI request completion with usage metrics (tokens, request counts, latency, etc. - no prompts or responses) |

## Event Properties

Expand Down Expand Up @@ -115,6 +116,24 @@ Each event may contain the following properties that are relevant to the particu
| `count:sshconn` | Total number of SSH connections |
| `count:wslconn` | Total number of WSL connections |
| `count:views` | Counts of the types of blocks (views) |
| `waveai:apitype` | AI API provider (OpenAI, Anthropic, etc.) |
| `waveai:model` | AI model name |
| `waveai:inputtokens` | Number of input tokens used |
| `waveai:outputtokens` | Number of output tokens generated |
| `waveai:requestcount` | Number of requests in conversation |
| `waveai:toolusecount` | Number of tool uses |
| `waveai:tooluseerrorcount` | Number of tool use errors |
| `waveai:tooldetail` | Map of tool names to usage counts |
| `waveai:premiumreq` | Number of premium API requests |
| `waveai:proxyreq` | Number of proxy requests |
| `waveai:haderror` | True/False if request had errors |
| `waveai:imagecount` | Number of images in context |
| `waveai:pdfcount` | Number of PDFs in context |
| `waveai:textdoccount` | Number of text documents in context |
| `waveai:textlen` | Total text length in context |
| `waveai:firstbytems` | Latency to first byte in milliseconds |
| `waveai:requestdurms` | Total request duration in milliseconds |
| `waveai:widgetaccess` | True/False if accessed via widget |

---

Expand Down
15 changes: 13 additions & 2 deletions docs/docs/waveai.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,18 @@ Drag files onto the AI panel to attach:
| PDFs | `.pdf` | 5 MB | Text extraction for analysis |
| Text/Code | `.js`, `.ts`, `.py`, `.go`, `.md`, `.json`, `.yaml`, etc. | 200 KB | All common languages and configs |

## CLI Integration

Use `wsh ai` to send files and prompts from the command line:

```bash
git diff | wsh ai - # Pipe to AI
wsh ai main.go -m "find bugs" # Attach files with message
wsh ai $(tail -n 500 my.log) -m "review" -s # Auto-submit with output
```

Supports text files, images, PDFs, and directories. Use `-n` for new chat, `-s` to auto-submit.

## AI Tools (Widget Context Enabled)

### Terminal
Expand All @@ -50,6 +62,7 @@ Drag files onto the AI panel to attach:
### File System
- **Read Files**: Reads text files with line range support (requires approval)
- **List Directories**: Returns file info, sizes, permissions, timestamps (requires approval)
- **Write Text Files**: Create or modify files with diff preview and approval (requires approval)

### Web
- **Navigate Web**: Changes URLs in web browser widgets
Expand All @@ -72,10 +85,8 @@ File system operations require explicit approval. You control all file access.
Wave AI is in active beta with included AI credits while we refine the experience. BYOK will be available once we've stabilized core features and gathered feedback on what works best. Share feedback in our [Discord](https://discord.gg/XfvZ334gwU).

**Coming Soon:**
- **CLI Integration**: Send files and chat prompts directly from the command line
- **Remote File Access**: Read files on SSH-connected systems
- **Command Execution**: Run terminal commands with approval
- **File Editing**: Modify files with approval or open in editor widgets
- **Web Content**: Extract text from web pages (currently screenshots only)
:::

Expand Down
2 changes: 1 addition & 1 deletion frontend/app/onboarding/onboarding-common.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2025, Command Line Inc.
// SPDX-License-Identifier: Apache-2.0

export const CurrentOnboardingVersion = "v0.12.1";
export const CurrentOnboardingVersion = "v0.12.2";
4 changes: 2 additions & 2 deletions frontend/app/onboarding/onboarding-features.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ 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 { CurrentOnboardingVersion } from "./onboarding-common";
import { FakeLayout } from "./onboarding-layout";

type FeaturePageName = "waveai" | "magnify" | "files";
Expand Down Expand Up @@ -100,7 +100,7 @@ const WaveAIPage = ({ onNext, onSkip }: { onNext: () => void; onSkip: () => void
<div className="flex flex-col items-start gap-4 text-secondary">
<p>
Wave AI is your terminal assistant with context. I can read your terminal output,
analyze widgets, access files, and help you solve problems faster.
analyze widgets, read/write files, and help you solve problems faster.
</p>

<div className="flex items-start gap-3 w-full">
Expand Down
165 changes: 165 additions & 0 deletions frontend/app/onboarding/onboarding-upgrade-patch.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
// 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";
import { UpgradeOnboardingModal_v0_12_1_Content } from "./onboarding-upgrade-v0121";
import { UpgradeOnboardingModal_v0_12_2_Content } from "./onboarding-upgrade-v0122";

interface VersionConfig {
version: string;
content: () => React.ReactNode;
prevText?: string;
nextText?: string;
}

const versions: VersionConfig[] = [
{
version: "v0.12.1",
content: () => <UpgradeOnboardingModal_v0_12_1_Content />,
nextText: "Next (v0.12.2)",
},
{
version: "v0.12.2",
content: () => <UpgradeOnboardingModal_v0_12_2_Content />,
prevText: "Prev (v0.12.1)",
},
];

const UpgradeOnboardingPatch = () => {
const modalRef = useRef<HTMLDivElement | null>(null);
const [isCompact, setIsCompact] = useState<boolean>(window.innerHeight < 800);
const [currentIndex, setCurrentIndex] = useState<number>(versions.length - 1);

const currentVersion = versions[currentIndex];
const hasPrev = currentIndex > 0;
const hasNext = currentIndex < versions.length - 1;

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]";

const handlePrev = () => {
if (hasPrev) {
setCurrentIndex(currentIndex - 1);
}
};

const handleNext = () => {
if (hasNext) {
setCurrentIndex(currentIndex + 1);
}
};

return (
<FlexiModal className={`w-[650px] rounded-[10px] ${paddingClass} relative overflow-hidden`} ref={modalRef}>
<div className="absolute inset-0 bg-gradient-to-br from-accent/[0.25] via-transparent to-accent/[0.05] pointer-events-none rounded-[10px]" />
<div className="flex flex-col w-full h-full relative z-10">
<div className="flex flex-col h-full">
<header className="flex flex-col gap-2 border-b-0 p-0 mt-1 mb-6 w-full unselectable flex-shrink-0">
<div className="flex justify-center">
<Logo />
</div>
<div className="text-center text-[25px] font-normal text-foreground">
Wave {currentVersion.version} Update
</div>
</header>
<OverlayScrollbarsComponent
className="flex-1 overflow-y-auto min-h-0"
options={{ scrollbars: { autoHide: "never" } }}
>
{currentVersion.content()}
</OverlayScrollbarsComponent>
<footer className="unselectable flex-shrink-0 mt-4">
<div className="flex flex-row items-center justify-between w-full">
<div className="flex-1 flex justify-start">
{hasPrev && (
<div className="text-sm text-secondary">
<button
onClick={handlePrev}
className="cursor-pointer hover:text-foreground transition-colors"
>
&lt; {currentVersion.prevText}
</button>
</div>
)}
</div>
<div className="flex flex-row items-center justify-center [&>button]:!px-5 [&>button]:!py-2 [&>button]:text-sm">
<Button className="font-[600]" onClick={handleClose}>
Continue
</Button>
</div>
<div className="flex-1 flex justify-end">
{hasNext && (
<div className="text-sm text-secondary">
<button
onClick={handleNext}
className="cursor-pointer hover:text-foreground transition-colors"
>
{currentVersion.nextText} &gt;
</button>
</div>
)}
</div>
</div>
</footer>
</div>
</div>
</FlexiModal>
);
};

UpgradeOnboardingPatch.displayName = "UpgradeOnboardingPatch";

export { UpgradeOnboardingPatch };
Loading
Loading