This PR extends WSH RPC command signatures to support `ctx + 2+ typed
args` while preserving existing `ctx` and `ctx + 1 arg` behavior. It
also adds a concrete `TestMultiArgCommand` end-to-end so the generated
Go/TS client surfaces can be inspected and exercised from CLI.
- **RPC wire + dispatch model**
- Added `wshrpc.MultiArg` (`args []any`) as the over-the-wire envelope
for 2+ arg commands.
- Extended RPC metadata to track all command arg types
(`CommandDataTypes`) and exposed a helper for normalized access.
- Updated server adapter unmarshalling to:
- decode `MultiArg` for 2+ arg commands,
- validate arg count,
- re-unmarshal each arg into its declared type before invoking typed
handlers.
- Kept single-arg commands on the existing non-`MultiArg` path.
- **Code generation (Go + TS)**
- Go codegen now emits multi-parameter wrappers for 2+ arg methods and
packs payload as `wshrpc.MultiArg`.
- TS codegen now emits multi-parameter API methods and packs payload as
`{ args: [...] }`.
- 0/1-arg generation remains unchanged to avoid wire/API churn.
- **Concrete command added for validation**
- Added to `WshRpcInterface`:
- `TestMultiArgCommand(ctx context.Context, arg1 string, arg2 int, arg3
bool) (string, error)`
- Implemented in `wshserver` with deterministic formatted return output
including source + all args.
- Updated `wsh test` command to call `TestMultiArgCommand` and print the
returned string.
- **Focused coverage**
- Added/updated targeted tests around RPC metadata and Go/TS multi-arg
codegen behavior, including command declaration for `testmultiarg`.
Example generated call shape:
```go
func TestMultiArgCommand(w *wshutil.WshRpc, arg1 string, arg2 int, arg3 bool, opts *wshrpc.RpcOpts) (string, error) {
return sendRpcRequestCallHelper[string](
w,
"testmultiarg",
wshrpc.MultiArg{Args: []any{arg1, arg2, arg3}},
opts,
)
}
```
<!-- START COPILOT CODING AGENT TIPS -->
---
💡 You can make Copilot smarter by setting up custom instructions,
customizing its development environment and configuring Model Context
Protocol (MCP) servers. Learn more [Copilot coding agent
tips](https://gh.io/copilot-coding-agent-tips) in the docs.
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: sawka <2722291+sawka@users.noreply.github.com>
Co-authored-by: sawka <mike@commandline.dev>
This follow-up tightens the new multi-file remote stat RPC behavior to
match expected usage: duplicate input paths are skipped, per-path stat
failures no longer fail the entire call, and cancellation is respected
during iteration.
- **RPC response model**
- Added `staterror` to `FileInfo`:
- `StatError string \`json:"staterror,omitempty"\``
- Generated TS type now exposes `staterror?: string` on `FileInfo`.
- **`RemoteFileMultiInfoCommand` behavior updates**
- **Dedup:** if an input path key is already present in the result map,
the loop continues.
- **Non-fatal stat failures:** on `fileInfoInternal` error, the command
now emits a `FileInfo` entry for that input with:
- resolved `path`, `dir`, `name`
- `staterror` populated with `err.Error()`
- continues processing remaining paths.
- **Cancellation:** checks `ctx.Err()` at the top of each iteration and
returns immediately if canceled.
- **PR scope cleanup**
- Removed the previously added test file from this PR per request.
```go
if _, found := rtn[path]; found {
continue
}
if ctx.Err() != nil {
return nil, ctx.Err()
}
fileInfo, err := impl.fileInfoInternal(cleanedPath, false)
if err != nil {
rtn[path] = wshrpc.FileInfo{
Path: wavebase.ReplaceHomeDir(cleanedPath),
Dir: computeDirPart(cleanedPath),
Name: filepath.Base(cleanedPath),
StatError: err.Error(),
}
continue
}
```
<!-- START COPILOT CODING AGENT TIPS -->
---
💬 We'd love your input! Share your thoughts on Copilot coding agent in
our [2 minute survey](https://gh.io/copilot-coding-agent-survey).
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: sawka <2722291+sawka@users.noreply.github.com>
* ConnMonitor to track stalled connections
* New Stalled Overlay to show feedback when we think a connection is
stalled
* New Icon in ConnButton to show stalled connections
* Callbacks in domain socket and PTYs to track activity
* Track wave version when job was created (for future backward compat)
* New Flyover Menu off of "shell durability" icon. Help + Actions + UX
* Bug with conn typeahead not closing when clicking disconnect
* Auto-reconnect jobs that have been disconnected (check for "gone"
state)
* Disable tab indicator stuff (only indicates tab not block)
* Fix bug with dev logging path on connserver
* Fix bugs with restarting blockcontrollers on startup
* Fix bugs with getting HasExited status from job manager
* Fix startup files, quoting, tilde, etc in start job flow
* ...
Working on bug fixes and UX. Streams restarting, fixed lots of bugs,
timing issues, concurrency bugs. Get status shipped to the FE to drive
"shield" state display. Deal with stale streams.
Also big UX changes to the block headers. Specialize the terminal
headers to prioritize the connection (sense of place), remove old
terminal icon and word "Terminal" from the header. Also drop "Web" and
"Preview" labels on web/preview blocks.
Added `wsh focusblock` command.
* Adds a Confirm on Quit dialog (and new config to disable it)
* New MacOS keybinding for Cmd:ArrowLeft/Cmd:ArrowRight to send Ctrl-A
and Ctrl-E respectively
* Fix Ctrl-V regression on windows to allow config setting to override
* Remove questionnaire in bug template
* Full featured tab indicators -- icon, color, priority, clear features.
Can be manipulated by new `wsh tabindicator` command
* Hook up BEL to new tab indicator system. BEL can now play a sound
and/or set an indicator (controlled by two new config options)
Big simplification. Remove the FileShare interface that abstracted
wsh://, s3://, and wavefile:// files.
It produced a lot of complexity for very little usage. We're just going
to focus on the wsh:// implementation since that's core to our remote
workflows.
* remove s3 implementation (and connections, and picker items for
preview)
* remove capabilities for FE
* remove wavefile backend impl as well
* simplify wsh file remote backend
* remove ability to copy/move/ls recursively
* limit file transfers to 32m
the longer term fix here is to use the new streaming RPC primitives.
they have full end-to-end flow-control built in and will not create
pipeline stalls, blocking other requests, and OOM issues.
these other impls had to be removed (or fixed) because transferring
large files could cause stalls or crashes with the new router
infrastructure.
Lots of updates across all parts of the system to get this working. Big
changes to routing, streaming, connection management, etc.
* Persistent sessions behind a metadata flag for now
* New backlog queue in the router to prevent hanging
* Fix connection Close() issues that caused hangs when network was down
* Fix issue with random routeids (need to be generated fresh each time
the JWT is used and not fixed) so you can run multiple-wsh commands at
once
* Fix issue with domain sockets changing names across wave restarts
(added a symlink mechanism to resolve new names)
* ClientId caching in main server
* Quick reorder queue for input to prevent out of order delivery across
multiple hops
* Fix out-of-order event delivery in router (remove unnecessary go
routine creation)
* Environment testing and fix environment variables for remote jobs (get
from connserver, add to remote job starts)
* Add new ConnServerInit() remote method to call before marking
connection up
* TODO -- remote file transfer needs to be fixed to not create OOM
issues when transferring large files or directories
lots of stuff here.
introduces a streaming framework for the RPC system with flow control.
new authentication primitives for the RPC system. this is used to create
a persistent "job manager" process (via wsh) that can survive
disconnects. and then a jobcontroller in the main server that can
create, reconnect, and manage these new persistent jobs.
code is currently not actively hooked up to anything minus some new
debugging wsh commands, and a switch in the term block that lets me test
viewing the output.
after PRing this change the next steps are more testing and then
integrating this functionality into the product.
the PR spiraled and ended up being much larger than anticipated.
it is a refactor of wshrouter to have it track "links" as opposed to
just routes. this lets us simplify a lot of things when it comes to
multi-level routing.
* now the router can handle unauthenticated links directly, instead of a
weird limbo in wshproxy
* no more wshmultiproxy
* no more "authtoken" weirdness
* more straightforward handling in connserver (when using router option)
also adds more debugging, more logging, some windows fixes, other wsl
fixes
* announce and unannounce should propagate
* route the sendmessage command
* add timeouts for sending to OutputCh (appropriately)
* add ctx for SendCancel function
tie the tool approvals to the lifecycle of the SSE connection, NOT FE
keepalive packets. this prevents timeouts when the FE hasn't rendered
the tools (or FE tool rendering lifecycle issues). also allows immediate
timeouts on refresh.
other small fixes: convert to use wshclient in wshcmd-*.go files,
cleanup in SSE code
* Kebab Menu + Switch App Functionality
* Updated Secrets Tab (still more to do, but closer)
* Better Error Handling (Switch to Secrets Tab)
* Add AppInit functionality to Tsunami (fixes initialization issues and
races with embedded assets, and error handling)
* Tsunami - ListStaticFiles
* Tsunami - More Robust Manifest generation (even when there are extra
stdout messages)
* load manifest metadata into the FE
* builder only edits draft/ apps (convert local => draft)
* gofmt app.go after saving (AI tools and manual user save)
* dont open duplicate builder windows
* remix app context menu in waveapp
* add icon/iconcolor in appmeta and implement in the wave block frame
* build manifest
* working on secrets injection (secretstore + secret-bindings.json)
* tool progress indicators
* build output and errors injected as the result of the edit calls so AI
gets instant feedback on edits
* change edits to not be atomic (allows AI to make better progress)
* updated binary location for waveapps
* publish button
* new partial json parser (for sending incremental tool progress
indication)
* updated tsunami view to use new embedded scaffold + config vars
* lots of work on cleaning up the output so it is more useful to users +
AI agents
* fix builder init flow
Handle both types of paste data. Write utility functions to normalize
paste events to {text; image}[]. Fix duplication issue (call
preventDefault() early). Handle multiple image pasting (by adding a
slight delay). Convert Ctrl:Shift:v to use a *native paste* which allows
capturing of images!
## Summary
This PR includes three terminal input improvements that enhance the
experience when using interactive CLI tools and IME input:
1. **Shift+Enter newline support**: Enable Shift+Enter to insert
newlines by default
2. **Image paste support**: Allow pasting images by saving them as
temporary files and pasting the file path
3. **IME duplicate input fix**: Fix duplicate text when switching input
methods during composition
## Motivation
### Shift+Enter for newlines
Currently, pressing Shift+Enter in the terminal behaves the same as
Enter, making it difficult to input multi-line commands or text in
interactive CLI tools. This change enables Shift+Enter to insert
newlines by default, matching common terminal emulator behavior.
### Image paste support
Interactive AI tools like Claude Code support receiving images through
file paths, but Wave Terminal currently doesn't support pasting images.
This change implements image paste functionality similar to iTerm2's
behavior: when an image is pasted, it's saved to a temporary file and
the path is pasted into the terminal.
### IME duplicate input fix
When using Chinese/Japanese/Korean IME in the terminal, switching input
methods with Capslock during composition causes the composed text to be
sent twice, resulting in duplicate output (e.g., "你好" becomes "你好你好").
This issue severely impacts users who frequently switch between
languages.
## Changes
### Shift+Enter newline (`frontend/app/view/term/term-model.ts`)
- Change default `shiftenternewline` config from `false` to `true`
- Send standard newline character (`\n`) instead of escape sequence
(`\^[\n`)
### Image paste (`frontend/app/view/term/term-model.ts`,
`frontend/app/view/term/termwrap.ts`)
- Add `handlePaste()` method to intercept Cmd+Shift+V paste events
- Add `handleImagePasteBlob()` to save images to `/tmp` and paste the
file path
- Detect image data in clipboard using both
`ClipboardEvent.clipboardData` and Clipboard API
- Support both screenshot paste and file copy scenarios
- Add 5MB size limit for pasted images
- Temporary files are created with format:
`waveterm_paste_[timestamp].[ext]`
### IME duplicate input fix (`frontend/app/view/term/termwrap.ts`,
`frontend/app/view/term/term-model.ts`)
**IME Composition Handling:**
- Track composition state (isComposing, composingData, etc.) in TermWrap
- Register compositionstart/update/end event listeners on xterm.js
textarea
- Block all data sends during composition, only allow after
compositionend
- Prevents xterm.js from sending intermediate data during
compositionupdate phase
**Deduplication Logic:**
- Implement 50ms time window deduplication for both IME and paste
operations
- Track first send after composition, block duplicate sends from
Capslock switching
- Ensure Ctrl+Space and Fn switching work correctly (single send only)
**Edge Case Handling:**
- Add blur event handler to reset composition state on focus loss
- Add Escape key handling to cancel composition in progress
## Testing
### Shift+Enter
1. Open a terminal in Wave
2. Press Shift+Enter
3. Verify that a newline is inserted instead of executing the command
### Image paste
1. Take a screenshot and copy it to clipboard (or copy an image file in
Finder)
2. In a terminal running Claude Code, paste the image (Cmd+V or
Cmd+Shift+V)
3. Verify that the image path appears and Claude Code recognizes it
### IME Input Testing
**IME Input:**
- [x] macOS Zhuyin IME + Capslock switching - no duplicate output ✅
- [x] macOS Zhuyin IME + Ctrl+Space switching - normal single input ✅
- [x] macOS Zhuyin IME + Fn switching - normal single input ✅
**Regression Testing:**
- [x] English keyboard input - normal operation ✅
- [x] Shift+Enter multiline input - works correctly ✅
- [x] Text paste (Cmd+Shift+V) - no duplicates ✅
- [x] Image paste - works correctly ✅
- [x] Basic command execution (ls, echo, etc.) - normal ✅
- [x] Cmd+K clear terminal - works correctly ✅
- [x] Copy selected text (Cmd+Shift+C) - works correctly ✅
## Demo
https://github.com/user-attachments/assets/8341cdf9-6c57-413e-b940-89e50cc79ff0https://github.com/user-attachments/assets/d3a6e72a-f488-45c1-ab58-88391639455ahttps://github.com/user-attachments/assets/ac178abd-caf3-40bf-9ef7-7cc0567a32c3
All features have been tested successfully on macOS with Claude Code in
Wave Terminal.
adds a new secret store protected by electron's safeStorage API.
currently just hooked up to the CLI via a new wsh command: `wsh secret`.
will be used to power secrets in tsunami later (and for config +
connections)
also updates ROADMAP.md, and fixes a node pruning bug on the FE, and
adds a new diff viewer that we can view the write_text_file and
edit_text_file diffs in. adds a backup file system that can be used to restore AI edited files back to their original states.
Got preview hooked up, log output hooked up, environment tab hooked
up... the controller, restarting the apps. it is actually working! still
lots to do and lots of hard coding to fix, but it is coming together...
- mark last command / prompts in xterm.js
- split out term model into its own file
- try to detect repl/shells/ssh/tmux etc commands that stop wave ai
integration
- show icons in term headers for whether wave ai integration is
available
- keep integration status / last command client side (sync with server
on reload)
### What This Does
Adds a new `wsh blocks list` subcommand that lists all blocks in all or
specified workspace, window, or tab. Includes filtering options and JSON
output for automation.
### Motivation
Wave users had no simple way to programmatically discover block IDs for
scripting and automation. This feature:
- Enables workflows like syncing Preview widgets with `cd` changes.
- Simplifies debugging and introspection.
- Provides a foundation for future CLI enhancements (focus/close
blocks).
### Usage
```wsh blocks [list|ls|get] [--workspace=<workspace-id>] [--window=<window-id>] [--tab=<tab-id>] [--view=<view-type>] [--json]```
Where `<view-type>` can be one of: term, terminal, shell, console, web, browser, url, preview, edit, sysinfo, sys, system, waveai, ai, or assistant.
### Notes
- Fully backward compatible.
- Code follows existing CLI patterns.
Massive PR, over 13k LOC updated, 128 commits to implement the first pass at the new Wave AI panel. Two backend adapters (OpenAI and Anthropic), layout changes to support the panel, keyboard shortcuts, and a huge focus/layout change to integrate the panel seamlessly into the UI.
Also fixes some small issues found during the Wave AI journey (zoom fixes, documentation, more scss removal, circular dependency issues, settings, etc)
checkpoint. good to merge. we have a working tsunami view inside of wave (with lots of caveats). but enough for some dev testing. merge so we dont drift too far from main and while we're at a stable point.
Gracefully handle prefix paths that don't exist, representing them as
directories so they can be escaped from.
Also removes the ".." file info from the backend, instead only creating
it on the frontend