Skip to content

Commit 2bf1bcc

Browse files
authored
v0.12.2 release notes, onboarding flow (#2518)
1 parent 2c53393 commit 2bf1bcc

File tree

9 files changed

+373
-166
lines changed

9 files changed

+373
-166
lines changed

docs/docs/releasenotes.mdx

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,26 @@ sidebar_position: 200
66

77
# Release Notes
88

9+
### v0.12.2 — Nov 4, 2025
10+
11+
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.
12+
13+
**Wave AI Updates:**
14+
- **File Write Tool** - Wave AI can now create and modify files with your approval
15+
- **Visual Diff Preview** - See exactly what will change before approving edits, rendered in Monaco Editor
16+
- **Easy Rollback** - Revert file changes with a simple "Revert File" button
17+
- **Drag & Drop Files** - Drag files from the preview viewer directly to Wave AI
18+
- **Directory Listings** - `wsh ai` can now attach directory listings to chats
19+
- **Adjustable Settings** - Control thinking level and max output tokens per chat
20+
21+
**Bug Fixes & Improvements:**
22+
- Fixed a significant memory leak in the RPC system
23+
- Schema validation working again for config files
24+
- Improved tool descriptions and input validations (run before tool approvals)
25+
- Fixed issue with premature tool timeouts
26+
- Fixed regression with PowerShell 5.x
27+
- Fixed prompt caching issue when attaching files
28+
929
### v0.12.1 — Oct 20, 2025
1030

1131
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.

docs/docs/telemetry.mdx

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ Below is a list of the event types collected in the new telemetry system. More e
7676
| `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 |
7777
| `conn:connect` | Logged each time a backend ssh/wsl connection connects (logs the conneciton type, no hostname or IP is sent) |
7878
| `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) |
79+
| `waveai:post` | Logged after AI request completion with usage metrics (tokens, request counts, latency, etc. - no prompts or responses) |
7980

8081
## Event Properties
8182

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

119138
---
120139

docs/docs/waveai.mdx

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,18 @@ Drag files onto the AI panel to attach:
4242
| PDFs | `.pdf` | 5 MB | Text extraction for analysis |
4343
| Text/Code | `.js`, `.ts`, `.py`, `.go`, `.md`, `.json`, `.yaml`, etc. | 200 KB | All common languages and configs |
4444

45+
## CLI Integration
46+
47+
Use `wsh ai` to send files and prompts from the command line:
48+
49+
```bash
50+
git diff | wsh ai - # Pipe to AI
51+
wsh ai main.go -m "find bugs" # Attach files with message
52+
wsh ai $(tail -n 500 my.log) -m "review" -s # Auto-submit with output
53+
```
54+
55+
Supports text files, images, PDFs, and directories. Use `-n` for new chat, `-s` to auto-submit.
56+
4557
## AI Tools (Widget Context Enabled)
4658

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

5467
### Web
5568
- **Navigate Web**: Changes URLs in web browser widgets
@@ -72,10 +85,8 @@ File system operations require explicit approval. You control all file access.
7285
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).
7386

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
// Copyright 2025, Command Line Inc.
22
// SPDX-License-Identifier: Apache-2.0
33

4-
export const CurrentOnboardingVersion = "v0.12.1";
4+
export const CurrentOnboardingVersion = "v0.12.2";

frontend/app/onboarding/onboarding-features.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ import { TabRpcClient } from "@/app/store/wshrpcutil";
1212
import { isMacOS } from "@/util/platformutil";
1313
import { useEffect, useState } from "react";
1414
import { FakeChat } from "./fakechat";
15-
import { CurrentOnboardingVersion } from "./onboarding-common";
1615
import { EditBashrcCommand, ViewLogoCommand, ViewShortcutsCommand } from "./onboarding-command";
16+
import { CurrentOnboardingVersion } from "./onboarding-common";
1717
import { FakeLayout } from "./onboarding-layout";
1818

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

106106
<div className="flex items-start gap-3 w-full">
Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
// Copyright 2025, Command Line Inc.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
import Logo from "@/app/asset/logo.svg";
5+
import { Button } from "@/app/element/button";
6+
import { FlexiModal } from "@/app/modals/modal";
7+
import { CurrentOnboardingVersion } from "@/app/onboarding/onboarding-common";
8+
import { atoms, globalStore } from "@/app/store/global";
9+
import { disableGlobalKeybindings, enableGlobalKeybindings, globalRefocus } from "@/app/store/keymodel";
10+
import { modalsModel } from "@/app/store/modalmodel";
11+
import * as WOS from "@/app/store/wos";
12+
import { RpcApi } from "@/app/store/wshclientapi";
13+
import { TabRpcClient } from "@/app/store/wshrpcutil";
14+
import { OverlayScrollbarsComponent } from "overlayscrollbars-react";
15+
import { useEffect, useRef, useState } from "react";
16+
import { debounce } from "throttle-debounce";
17+
import { UpgradeOnboardingModal_v0_12_1_Content } from "./onboarding-upgrade-v0121";
18+
import { UpgradeOnboardingModal_v0_12_2_Content } from "./onboarding-upgrade-v0122";
19+
20+
interface VersionConfig {
21+
version: string;
22+
content: () => React.ReactNode;
23+
prevText?: string;
24+
nextText?: string;
25+
}
26+
27+
const versions: VersionConfig[] = [
28+
{
29+
version: "v0.12.1",
30+
content: () => <UpgradeOnboardingModal_v0_12_1_Content />,
31+
nextText: "Next (v0.12.2)",
32+
},
33+
{
34+
version: "v0.12.2",
35+
content: () => <UpgradeOnboardingModal_v0_12_2_Content />,
36+
prevText: "Prev (v0.12.1)",
37+
},
38+
];
39+
40+
const UpgradeOnboardingPatch = () => {
41+
const modalRef = useRef<HTMLDivElement | null>(null);
42+
const [isCompact, setIsCompact] = useState<boolean>(window.innerHeight < 800);
43+
const [currentIndex, setCurrentIndex] = useState<number>(versions.length - 1);
44+
45+
const currentVersion = versions[currentIndex];
46+
const hasPrev = currentIndex > 0;
47+
const hasNext = currentIndex < versions.length - 1;
48+
49+
const updateModalHeight = () => {
50+
const windowHeight = window.innerHeight;
51+
setIsCompact(windowHeight < 800);
52+
if (modalRef.current) {
53+
const modalHeight = modalRef.current.offsetHeight;
54+
const maxHeight = windowHeight * 0.9;
55+
if (maxHeight < modalHeight) {
56+
modalRef.current.style.height = `${maxHeight}px`;
57+
} else {
58+
modalRef.current.style.height = "auto";
59+
}
60+
}
61+
};
62+
63+
useEffect(() => {
64+
updateModalHeight();
65+
const debouncedUpdateModalHeight = debounce(150, updateModalHeight);
66+
window.addEventListener("resize", debouncedUpdateModalHeight);
67+
return () => {
68+
window.removeEventListener("resize", debouncedUpdateModalHeight);
69+
};
70+
}, []);
71+
72+
useEffect(() => {
73+
disableGlobalKeybindings();
74+
return () => {
75+
enableGlobalKeybindings();
76+
};
77+
}, []);
78+
79+
const handleClose = () => {
80+
const clientId = globalStore.get(atoms.clientId);
81+
RpcApi.SetMetaCommand(TabRpcClient, {
82+
oref: WOS.makeORef("client", clientId),
83+
meta: { "onboarding:lastversion": CurrentOnboardingVersion },
84+
});
85+
globalStore.set(modalsModel.upgradeOnboardingOpen, false);
86+
setTimeout(() => {
87+
globalRefocus();
88+
}, 10);
89+
};
90+
91+
const paddingClass = isCompact ? "!py-3 !px-[30px]" : "!p-[30px]";
92+
93+
const handlePrev = () => {
94+
if (hasPrev) {
95+
setCurrentIndex(currentIndex - 1);
96+
}
97+
};
98+
99+
const handleNext = () => {
100+
if (hasNext) {
101+
setCurrentIndex(currentIndex + 1);
102+
}
103+
};
104+
105+
return (
106+
<FlexiModal className={`w-[650px] rounded-[10px] ${paddingClass} relative overflow-hidden`} ref={modalRef}>
107+
<div className="absolute inset-0 bg-gradient-to-br from-accent/[0.25] via-transparent to-accent/[0.05] pointer-events-none rounded-[10px]" />
108+
<div className="flex flex-col w-full h-full relative z-10">
109+
<div className="flex flex-col h-full">
110+
<header className="flex flex-col gap-2 border-b-0 p-0 mt-1 mb-6 w-full unselectable flex-shrink-0">
111+
<div className="flex justify-center">
112+
<Logo />
113+
</div>
114+
<div className="text-center text-[25px] font-normal text-foreground">
115+
Wave {currentVersion.version} Update
116+
</div>
117+
</header>
118+
<OverlayScrollbarsComponent
119+
className="flex-1 overflow-y-auto min-h-0"
120+
options={{ scrollbars: { autoHide: "never" } }}
121+
>
122+
{currentVersion.content()}
123+
</OverlayScrollbarsComponent>
124+
<footer className="unselectable flex-shrink-0 mt-4">
125+
<div className="flex flex-row items-center justify-between w-full">
126+
<div className="flex-1 flex justify-start">
127+
{hasPrev && (
128+
<div className="text-sm text-secondary">
129+
<button
130+
onClick={handlePrev}
131+
className="cursor-pointer hover:text-foreground transition-colors"
132+
>
133+
&lt; {currentVersion.prevText}
134+
</button>
135+
</div>
136+
)}
137+
</div>
138+
<div className="flex flex-row items-center justify-center [&>button]:!px-5 [&>button]:!py-2 [&>button]:text-sm">
139+
<Button className="font-[600]" onClick={handleClose}>
140+
Continue
141+
</Button>
142+
</div>
143+
<div className="flex-1 flex justify-end">
144+
{hasNext && (
145+
<div className="text-sm text-secondary">
146+
<button
147+
onClick={handleNext}
148+
className="cursor-pointer hover:text-foreground transition-colors"
149+
>
150+
{currentVersion.nextText} &gt;
151+
</button>
152+
</div>
153+
)}
154+
</div>
155+
</div>
156+
</footer>
157+
</div>
158+
</div>
159+
</FlexiModal>
160+
);
161+
};
162+
163+
UpgradeOnboardingPatch.displayName = "UpgradeOnboardingPatch";
164+
165+
export { UpgradeOnboardingPatch };

0 commit comments

Comments
 (0)