merge v0.8.13 changes
2
.github/workflows/build-helper.yml
vendored
@ -3,7 +3,7 @@
|
||||
# For more information on the Windows Code Signing, see https://docs.digicert.com/en/digicert-keylocker/ci-cd-integrations/plugins/github-custom-action-for-keypair-signing.html and https://docs.digicert.com/en/digicert-keylocker/signing-tools/sign-authenticode-with-electron-builder-using-ksp-integration.html
|
||||
|
||||
name: Build Helper
|
||||
run-name: Build ${{ github.ref_name }}${{ github.event_name == 'workflow_dispatch' && ' - Manual'}}
|
||||
run-name: Build ${{ github.ref_name }}${{ github.event_name == 'workflow_dispatch' && ' - Manual' || '' }}
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
|
17
.github/workflows/publish-release.yml
vendored
@ -16,6 +16,9 @@ jobs:
|
||||
with:
|
||||
version: 3.x
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Install Snapcraft
|
||||
run: sudo snap install snapcraft --classic
|
||||
shell: bash
|
||||
- name: Publish from staging
|
||||
run: "task artifacts:publish:${{ github.ref_name }}"
|
||||
env:
|
||||
@ -23,6 +26,16 @@ jobs:
|
||||
AWS_SECRET_ACCESS_KEY: "${{ secrets.PUBLISHER_KEY_SECRET }}"
|
||||
AWS_DEFAULT_REGION: us-west-2
|
||||
shell: bash
|
||||
- name: Download Snap from Release
|
||||
uses: robinraju/release-downloader@v1
|
||||
with:
|
||||
tag: ${{github.ref_name}}
|
||||
fileName: "*.snap"
|
||||
- name: Publish to Snapcraft
|
||||
run: "task artifacts:snap:publish:${{ github.ref_name }}"
|
||||
env:
|
||||
SNAPCRAFT_STORE_CREDENTIALS: "${{secrets.SNAPCRAFT_LOGIN_CREDS}}"
|
||||
shell: bash
|
||||
bump-winget:
|
||||
if: ${{ startsWith(github.ref, 'refs/tags/') && !contains(github.ref_name, 'beta') }}
|
||||
runs-on: windows-latest
|
||||
@ -33,8 +46,8 @@ jobs:
|
||||
with:
|
||||
version: 3.x
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Submit Winget version bump
|
||||
run: "task artifacts:publish:winget:${{ github.ref_name }}"
|
||||
- name: Submit WinGet version bump
|
||||
run: "task artifacts:winget:publish:${{ github.ref_name }}"
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.WINGET_BUMP_PAT }}
|
||||
shell: pwsh
|
||||
|
21
BUILD.md
@ -35,6 +35,19 @@ Arch:
|
||||
sudo pacman -S zip zig
|
||||
```
|
||||
|
||||
##### For packaging
|
||||
|
||||
For packaging, the following additional packages are required:
|
||||
|
||||
- `fpm` — If you're on x64 you can skip this. If you're on ARM64, install fpm via [Gem](https://rubygems.org/gems/fpm)
|
||||
- `rpm` — If you're not on Fedora, install RPM via your package manager.
|
||||
- `snapd` — If your distro doesn't already include it, [install `snapd`](https://snapcraft.io/docs/installing-snapd)
|
||||
- `lxd` — [Installation instructions](https://canonical.com/lxd/install)
|
||||
- `snapcraft` — Run `sudo snap install snapcraft --classic`
|
||||
- `libarchive-tools` — Install via your package manager
|
||||
- `libopenjp2-tools` — Install via your package manager
|
||||
- `squashfs-tools` — Install via your package manager
|
||||
|
||||
#### Windows
|
||||
|
||||
You will need the GNU build toolchain installed in order for Go to work on Windows. In most cases, this requires installing MinGW-w64.
|
||||
@ -55,7 +68,7 @@ Download and install Go via your package manager or directly from the website: h
|
||||
|
||||
### NodeJS
|
||||
|
||||
Make sure you have a recent version of NodeJS installed (>= 20).
|
||||
Make sure you have a NodeJS 20 LTS installed.
|
||||
|
||||
See NodeJS's website for platform-specific instructions: https://nodejs.org/en/download
|
||||
|
||||
@ -118,6 +131,12 @@ Run the following command to generate a production build and package it. This le
|
||||
task package
|
||||
```
|
||||
|
||||
If you're on Linux ARM64, run the following:
|
||||
|
||||
```sh
|
||||
USE_SYSTEM_FPM=1 task package
|
||||
```
|
||||
|
||||
## Debugging
|
||||
|
||||
### Frontend logs
|
||||
|
@ -29,6 +29,12 @@ Also available as a Homebrew Cask for macOS:
|
||||
brew install --cask wave
|
||||
```
|
||||
|
||||
Also available as a [Snap](https://snapcraft.io/waveterm) on Linux:
|
||||
|
||||
```bash
|
||||
sudo snap install waveterm --classic
|
||||
```
|
||||
|
||||
Also available via the Windows Package Manager:
|
||||
|
||||
```Powershell
|
||||
|
13
Taskfile.yml
@ -230,11 +230,20 @@ tasks:
|
||||
echo "https://$SUFFIX"
|
||||
fi
|
||||
done
|
||||
artifacts:snap:publish:*:
|
||||
desc: Publishes the specified artifacts version to Snapcraft.
|
||||
vars:
|
||||
UP_VERSION: '{{ replace "v" "" (index .MATCH 0)}}'
|
||||
CHANNEL: '{{if contains "beta" .UP_VERSION}}beta{{else}}beta,stable{{end}}'
|
||||
cmd: |
|
||||
echo "Releasing to channels: [{{.CHANNEL}}]"
|
||||
snapcraft upload --release={{.CHANNEL}} waveterm_{{.UP_VERSION}}_arm64.snap
|
||||
snapcraft upload --release={{.CHANNEL}} waveterm_{{.UP_VERSION}}_amd64.snap
|
||||
|
||||
artifacts:publish:winget:*:
|
||||
artifacts:winget:publish:*:
|
||||
desc: Submits a version bump request to WinGet for the latest release.
|
||||
status:
|
||||
- exit {{if contains UP_VERSION "beta"}}0{{else}}1{{end}}
|
||||
- exit {{if contains "beta" .UP_VERSION}}0{{else}}1{{end}}
|
||||
vars:
|
||||
UP_VERSION: '{{ replace "v" "" (index .MATCH 0)}}'
|
||||
cmd: |
|
||||
|
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 37 KiB |
@ -1,20 +1,84 @@
|
||||
<svg width="1024" height="727" viewBox="0 0 1024 727" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M328.87 332.526C280.49 332.526 253.744 364.034 239.191 434.533L20.5 403.025C47.2464 172.231 136.925 60.3787 314.317 60.3787C445.688 60.3787 574.307 160.022 637.24 160.022C686.012 160.022 712.365 126.151 726.918 58.0156L945.609 89.5233C921.223 320.711 829.184 432.563 651.793 432.563C518.454 432.17 394.556 332.526 328.87 332.526Z"
|
||||
fill="url(#paint0_linear_1814_3217)" />
|
||||
<path
|
||||
d="M390.87 558.061C342.49 558.061 315.744 589.569 301.191 660.067L82.5 628.559C109.246 397.765 198.925 285.519 376.317 285.519C507.295 285.519 636.307 385.162 699.239 385.162C748.012 385.162 774.365 351.292 788.918 283.156L1007.61 314.664C983.223 545.852 891.184 657.704 713.793 657.704C580.454 657.704 456.556 558.061 390.87 558.061Z"
|
||||
fill="url(#paint1_linear_1814_3217)" />
|
||||
<defs>
|
||||
<linearGradient id="paint0_linear_1814_3217" x1="20.5503" y1="246.309" x2="945.797" y2="246.309"
|
||||
gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0.1418" stop-color="#1F4D22" />
|
||||
<stop offset="0.8656" stop-color="#418D31" />
|
||||
</linearGradient>
|
||||
<linearGradient id="paint1_linear_1814_3217" x1="82.5673" y1="471.774" x2="1007.81" y2="471.774"
|
||||
gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0.2223" stop-color="#418D31" />
|
||||
<stop offset="0.7733" stop-color="#58C142" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
width="1024"
|
||||
height="1024"
|
||||
viewBox="0 0 1024 1024"
|
||||
fill="none"
|
||||
version="1.1"
|
||||
id="svg5"
|
||||
sodipodi:docname="appicon-windows.svg"
|
||||
inkscape:version="1.4 (e7c3feb1, 2024-10-09)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<sodipodi:namedview
|
||||
id="namedview5"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#000000"
|
||||
borderopacity="0.25"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
showgrid="false"
|
||||
borderlayer="false"
|
||||
inkscape:zoom="0.99449794"
|
||||
inkscape:cx="511.31328"
|
||||
inkscape:cy="524.3852"
|
||||
inkscape:window-width="2288"
|
||||
inkscape:window-height="1186"
|
||||
inkscape:window-x="3103"
|
||||
inkscape:window-y="25"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="svg5" />
|
||||
<g
|
||||
id="g5"
|
||||
transform="translate(-2.055,152.9587)">
|
||||
<path
|
||||
d="m 328.87,332.526 c -48.38,0 -75.126,31.508 -89.679,102.007 L 20.5,403.025 C 47.2464,172.231 136.925,60.3787 314.317,60.3787 c 131.371,0 259.99,99.6433 322.923,99.6433 48.772,0 75.125,-33.871 89.678,-102.0064 L 945.609,89.5233 C 921.223,320.711 829.184,432.563 651.793,432.563 518.454,432.17 394.556,332.526 328.87,332.526 Z"
|
||||
fill="url(#paint0_linear_1814_3217)"
|
||||
id="path1"
|
||||
style="fill:url(#paint0_linear_1814_3217)" />
|
||||
<path
|
||||
d="m 390.87,558.061 c -48.38,0 -75.126,31.508 -89.679,102.006 L 82.5,628.559 c 26.746,-230.794 116.425,-343.04 293.817,-343.04 130.978,0 259.99,99.643 322.922,99.643 48.773,0 75.126,-33.87 89.679,-102.006 l 218.692,31.508 c -24.387,231.188 -116.426,343.04 -293.817,343.04 -133.339,0 -257.237,-99.643 -322.923,-99.643 z"
|
||||
fill="url(#paint1_linear_1814_3217)"
|
||||
id="path2"
|
||||
style="fill:url(#paint1_linear_1814_3217)" />
|
||||
</g>
|
||||
<defs
|
||||
id="defs5">
|
||||
<linearGradient
|
||||
id="paint0_linear_1814_3217"
|
||||
x1="20.550301"
|
||||
y1="246.30901"
|
||||
x2="945.797"
|
||||
y2="246.30901"
|
||||
gradientUnits="userSpaceOnUse">
|
||||
<stop
|
||||
offset="0.1418"
|
||||
stop-color="#1F4D22"
|
||||
id="stop2" />
|
||||
<stop
|
||||
offset="0.8656"
|
||||
stop-color="#418D31"
|
||||
id="stop3" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="paint1_linear_1814_3217"
|
||||
x1="82.567299"
|
||||
y1="471.77399"
|
||||
x2="1007.81"
|
||||
y2="471.77399"
|
||||
gradientUnits="userSpaceOnUse">
|
||||
<stop
|
||||
offset="0.2223"
|
||||
stop-color="#418D31"
|
||||
id="stop4" />
|
||||
<stop
|
||||
offset="0.7733"
|
||||
stop-color="#58C142"
|
||||
id="stop5" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 2.8 KiB |
BIN
build/icons/128x128.png
Normal file
After Width: | Height: | Size: 6.2 KiB |
BIN
build/icons/16x16.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
build/icons/256x256.png
Normal file
After Width: | Height: | Size: 13 KiB |
BIN
build/icons/32x32.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
build/icons/512x512.png
Normal file
After Width: | Height: | Size: 31 KiB |
@ -88,6 +88,7 @@ const config = {
|
||||
base: "core22",
|
||||
confinement: "classic",
|
||||
allowNativeWayland: true,
|
||||
artifactName: "${name}_${version}_${arch}.${ext}",
|
||||
},
|
||||
publish: {
|
||||
provider: "generic",
|
||||
|
@ -17,6 +17,7 @@ import {
|
||||
getConnStatusAtom,
|
||||
getSettingsKeyAtom,
|
||||
globalStore,
|
||||
useBlockAtom,
|
||||
useSettingsPrefixAtom,
|
||||
} from "@/store/global";
|
||||
import * as services from "@/store/services";
|
||||
@ -55,6 +56,8 @@ class TermViewModel {
|
||||
termWshClient: TermWshClient;
|
||||
shellProcStatusRef: React.MutableRefObject<string>;
|
||||
vdomBlockId: jotai.Atom<string>;
|
||||
fontSizeAtom: jotai.Atom<number>;
|
||||
termThemeNameAtom: jotai.Atom<string>;
|
||||
|
||||
constructor(blockId: string, nodeModel: NodeModel) {
|
||||
this.viewType = "term";
|
||||
@ -145,6 +148,25 @@ class TermViewModel {
|
||||
const connAtom = getConnStatusAtom(connName);
|
||||
return get(connAtom);
|
||||
});
|
||||
this.fontSizeAtom = useBlockAtom(blockId, "fontsizeatom", () => {
|
||||
return jotai.atom<number>((get) => {
|
||||
const blockData = get(this.blockAtom);
|
||||
const fsSettingsAtom = getSettingsKeyAtom("term:fontsize");
|
||||
const settingsFontSize = get(fsSettingsAtom);
|
||||
const rtnFontSize = blockData?.meta?.["term:fontsize"] ?? settingsFontSize ?? 12;
|
||||
if (typeof rtnFontSize != "number" || isNaN(rtnFontSize) || rtnFontSize < 4 || rtnFontSize > 64) {
|
||||
return 12;
|
||||
}
|
||||
return rtnFontSize;
|
||||
});
|
||||
});
|
||||
this.termThemeNameAtom = useBlockAtom(blockId, "termthemeatom", () => {
|
||||
return jotai.atom<string>((get) => {
|
||||
const blockData = get(this.blockAtom);
|
||||
const settingsKeyAtom = getSettingsKeyAtom("term:theme");
|
||||
return blockData?.meta?.["term:theme"] ?? get(settingsKeyAtom) ?? "default-dark";
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
setTermMode(mode: "term" | "vdom") {
|
||||
@ -257,6 +279,10 @@ class TermViewModel {
|
||||
const fullConfig = globalStore.get(atoms.fullConfigAtom);
|
||||
const termThemes = fullConfig?.termthemes ?? {};
|
||||
const termThemeKeys = Object.keys(termThemes);
|
||||
const curThemeName = globalStore.get(this.termThemeNameAtom);
|
||||
const defaultFontSize = globalStore.get(getSettingsKeyAtom("term:fontsize")) ?? 12;
|
||||
const blockData = globalStore.get(this.blockAtom);
|
||||
const overrideFontSize = blockData?.meta?.["term:fontsize"];
|
||||
|
||||
termThemeKeys.sort((a, b) => {
|
||||
return termThemes[a]["display:order"] - termThemes[b]["display:order"];
|
||||
@ -265,13 +291,45 @@ class TermViewModel {
|
||||
const submenu: ContextMenuItem[] = termThemeKeys.map((themeName) => {
|
||||
return {
|
||||
label: termThemes[themeName]["display:name"] ?? themeName,
|
||||
type: "checkbox",
|
||||
checked: curThemeName == themeName,
|
||||
click: () => this.setTerminalTheme(themeName),
|
||||
};
|
||||
});
|
||||
const fontSizeSubMenu: ContextMenuItem[] = [6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18].map(
|
||||
(fontSize: number) => {
|
||||
return {
|
||||
label: fontSize.toString() + "px",
|
||||
type: "checkbox",
|
||||
checked: overrideFontSize == fontSize,
|
||||
click: () => {
|
||||
RpcApi.SetMetaCommand(TabRpcClient, {
|
||||
oref: WOS.makeORef("block", this.blockId),
|
||||
meta: { "term:fontsize": fontSize },
|
||||
});
|
||||
},
|
||||
};
|
||||
}
|
||||
);
|
||||
fontSizeSubMenu.unshift({
|
||||
label: "Default (" + defaultFontSize + "px)",
|
||||
type: "checkbox",
|
||||
checked: overrideFontSize == null,
|
||||
click: () => {
|
||||
RpcApi.SetMetaCommand(TabRpcClient, {
|
||||
oref: WOS.makeORef("block", this.blockId),
|
||||
meta: { "term:fontsize": null },
|
||||
});
|
||||
},
|
||||
});
|
||||
fullMenu.push({
|
||||
label: "Themes",
|
||||
submenu: submenu,
|
||||
});
|
||||
fullMenu.push({
|
||||
label: "Font Size",
|
||||
submenu: fontSizeSubMenu,
|
||||
});
|
||||
fullMenu.push({ type: "separator" });
|
||||
fullMenu.push({
|
||||
label: "Force Restart Controller",
|
||||
@ -386,6 +444,8 @@ const TerminalView = ({ blockId, model }: TerminalViewProps) => {
|
||||
}
|
||||
const termModeRef = React.useRef(termMode);
|
||||
|
||||
const termFontSize = jotai.useAtomValue(model.fontSizeAtom);
|
||||
|
||||
React.useEffect(() => {
|
||||
const fullConfig = globalStore.get(atoms.fullConfigAtom);
|
||||
const termTheme = computeTheme(fullConfig, blockData?.meta?.["term:theme"]);
|
||||
@ -404,12 +464,13 @@ const TerminalView = ({ blockId, model }: TerminalViewProps) => {
|
||||
if (termScrollback > 10000) {
|
||||
termScrollback = 10000;
|
||||
}
|
||||
const wasFocused = termRef.current != null && globalStore.get(model.nodeModel.isFocused);
|
||||
const termWrap = new TermWrap(
|
||||
blockId,
|
||||
connectElemRef.current,
|
||||
{
|
||||
theme: themeCopy,
|
||||
fontSize: termSettings?.["term:fontsize"] ?? 12,
|
||||
fontSize: termFontSize,
|
||||
fontFamily: termSettings?.["term:fontfamily"] ?? "Hack",
|
||||
drawBoldTextInBrightColors: false,
|
||||
fontWeight: "normal",
|
||||
@ -429,11 +490,16 @@ const TerminalView = ({ blockId, model }: TerminalViewProps) => {
|
||||
});
|
||||
rszObs.observe(connectElemRef.current);
|
||||
termWrap.initTerminal();
|
||||
if (wasFocused) {
|
||||
setTimeout(() => {
|
||||
model.giveFocus();
|
||||
}, 10);
|
||||
}
|
||||
return () => {
|
||||
termWrap.dispose();
|
||||
rszObs.disconnect();
|
||||
};
|
||||
}, [blockId, termSettings]);
|
||||
}, [blockId, termSettings, termFontSize]);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (termModeRef.current == "vdom" && termMode == "term") {
|
||||
|
@ -7,7 +7,7 @@
|
||||
"productName": "Wave",
|
||||
"description": "Open-Source AI-Native Terminal Built for Seamless Workflows",
|
||||
"license": "Apache-2.0",
|
||||
"version": "0.8.12",
|
||||
"version": "0.8.13-beta.3",
|
||||
"homepage": "https://waveterm.dev",
|
||||
"build": {
|
||||
"appId": "dev.commandline.waveterm"
|
||||
|
@ -20,7 +20,7 @@ import (
|
||||
"golang.org/x/crypto/ssh"
|
||||
)
|
||||
|
||||
var userHostRe = regexp.MustCompile(`^([a-zA-Z0-9][a-zA-Z0-9._@\\-]*@)?([a-z0-9][a-z0-9.-]*)(?::([0-9]+))?$`)
|
||||
var userHostRe = regexp.MustCompile(`^([a-zA-Z0-9][a-zA-Z0-9._@\\-]*@)?([a-zA-Z0-9][a-zA-Z0-9.-]*)(?::([0-9]+))?$`)
|
||||
|
||||
func ParseOpts(input string) (*SSHOpts, error) {
|
||||
m := userHostRe.FindStringSubmatch(input)
|
||||
|
@ -4,6 +4,8 @@ import (
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
"runtime"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/creack/pty"
|
||||
@ -43,7 +45,11 @@ func (cw CmdWrap) KillGraceful(timeout time.Duration) {
|
||||
if cw.Cmd.ProcessState != nil && cw.Cmd.ProcessState.Exited() {
|
||||
return
|
||||
}
|
||||
cw.Cmd.Process.Signal(os.Interrupt)
|
||||
if runtime.GOOS == "windows" {
|
||||
cw.Cmd.Process.Signal(os.Interrupt)
|
||||
} else {
|
||||
cw.Cmd.Process.Signal(syscall.SIGTERM)
|
||||
}
|
||||
go func() {
|
||||
time.Sleep(timeout)
|
||||
if cw.Cmd.ProcessState == nil || !cw.Cmd.ProcessState.Exited() {
|
||||
|
@ -863,9 +863,9 @@ func AtomicRenameCopy(dstPath string, srcPath string, perms os.FileMode) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer dstFd.Close()
|
||||
_, err = io.Copy(dstFd, srcFd)
|
||||
if err != nil {
|
||||
dstFd.Close()
|
||||
return err
|
||||
}
|
||||
err = dstFd.Close()
|
||||
|
@ -231,10 +231,11 @@ func checkIsReadOnly(path string, fileInfo fs.FileInfo, exists bool) bool {
|
||||
return false
|
||||
}
|
||||
tmpFileName := filepath.Join(dirName, "wsh-tmp-"+randHexStr)
|
||||
_, err = os.Create(tmpFileName)
|
||||
fd, err := os.Create(tmpFileName)
|
||||
if err != nil {
|
||||
return true
|
||||
}
|
||||
fd.Close()
|
||||
os.Remove(tmpFileName)
|
||||
return false
|
||||
}
|
||||
|