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
46 changes: 45 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,49 @@ jobs:
- run: bun install --frozen-lockfile
- run: bun test
- run: bunx tsc -p .
- run: sh -n install.sh
- run: sh -n install.sh && bash -n install.sh
- run: bun build --compile src/main.ts --outfile dist/hqterm && ./dist/hqterm --version

desktop:
runs-on: ubuntu-latest
defaults:
run:
working-directory: desktop
steps:
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v2
with:
bun-version: latest
- uses: actions/setup-node@v4
with:
node-version: 22
- run: npm ci
- run: npm test
- name: Build AppImage
run: npm run dist
- name: Smoke test under Xvfb (window, PTYs, images, split, layout restore)
run: |
ls -la dist
app="$(ls dist/*.AppImage | head -n1)"
smoke() {
HQTERM_DESKTOP_SMOKE=10000 HQTERM_DESKTOP_SMOKE_SHOT="$PWD/$1" XDG_CONFIG_HOME="$RUNNER_TEMP/cfg" \
xvfb-run -a -s "-screen 0 1280x800x24" "$app" --appimage-extract-and-run --no-sandbox 2>&1 | grep -v appimage_extracted | tee "$1.log"
}
# First launch: one shell, then Ctrl+Shift+D splits it (2 PTYs).
smoke smoke-1.png
grep -q "hqterm-desktop smoke: ok (ptys=2)" smoke-1.png.log
cat "$RUNNER_TEMP/cfg/hqterm/desktop-layout.json"
# Second launch restores both panes, then splits again (3 PTYs).
smoke smoke-2.png
grep -q "hqterm-desktop smoke: ok (ptys=3)" smoke-2.png.log
- uses: actions/upload-artifact@v4
if: always()
with:
name: hqterm-desktop-smoke-screenshot
path: desktop/smoke-*.png
retention-days: 7
- uses: actions/upload-artifact@v4
with:
name: hqterm-desktop-linux-x86_64
path: desktop/dist/*.AppImage
retention-days: 7
53 changes: 53 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,52 @@ permissions:
contents: write

jobs:
desktop:
strategy:
matrix:
include:
- runner: ubuntu-latest
arch: x86_64
- runner: ubuntu-24.04-arm
arch: aarch64
runs-on: ${{ matrix.runner }}
# arm64 is a bonus: its failure must not hold back the x86_64 release.
continue-on-error: ${{ matrix.arch == 'aarch64' }}
defaults:
run:
working-directory: desktop
steps:
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v2
with:
bun-version: latest
- uses: actions/setup-node@v4
with:
node-version: 22
- name: Tag matches desktop/package.json
run: |
want="v$(node -p 'require("./package.json").version')"
[ "$want" = "$GITHUB_REF_NAME" ] || { echo "tag $GITHUB_REF_NAME but desktop/package.json says $want"; exit 1; }
- run: npm ci
- run: npm test
- run: npm run dist
- name: Name the AppImage
run: |
app="$(ls dist/*.AppImage | head -n1)"
mv "$app" "dist/hqterm-desktop-linux-${{ matrix.arch }}.AppImage"
ls -la dist
- name: Smoke test under Xvfb
run: |
if ! command -v xvfb-run >/dev/null; then sudo apt-get update -qq && sudo apt-get install -y -qq xvfb; fi
HQTERM_DESKTOP_SMOKE=8000 XDG_CONFIG_HOME="$RUNNER_TEMP/cfg" xvfb-run -a "dist/hqterm-desktop-linux-${{ matrix.arch }}.AppImage" --appimage-extract-and-run --no-sandbox 2>&1 | grep -v appimage_extracted | tee smoke.log
grep -q "hqterm-desktop smoke: ok" smoke.log
- uses: actions/upload-artifact@v4
with:
name: desktop-${{ matrix.arch }}
path: desktop/dist/hqterm-desktop-linux-${{ matrix.arch }}.AppImage

release:
needs: desktop
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
Expand All @@ -28,6 +73,14 @@ jobs:
target="bun-${t%%:*}"; name="hqterm-${t##*:}"
bun build --compile --minify --target="$target" src/main.ts --outfile "dist/$name"
done
- uses: actions/download-artifact@v4
with:
pattern: desktop-*
path: dist
merge-multiple: true
- name: Checksums
run: |
cp desktop/build/icon.png dist/hqterm-desktop.png
cd dist && sha256sum hqterm-* > SHA256SUMS && cat SHA256SUMS
- name: Smoke test
run: ./dist/hqterm-linux-amd64 --version
Expand Down
43 changes: 42 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,46 @@ In the manager: Enter or one click attaches, `n` new session, `a` add host,
`i` install hqsh on the host, `r` refresh, `q` quit. Inside a session,
`Ctrl-^ .` detaches and returns to hqterm.

## Desktop app

`hqterm desktop [--host H] [--session S]` opens hqterm's own terminal window
(Electron + xterm.js): tabs, split panes, and hqtui/qc images and HD emoji drawn
via iTerm2 inline images and sixel, plus the OpenEmoji colour font, so it works
where Konsole and friends cannot. Every pane gets `TERM_PROGRAM=hqterm`,
`HQTUI_IMAGES=iterm` and `QC_HD=iterm`.

```sh
curl -fsSL https://hqterm.sh/install | sh -s -- --desktop
hqterm desktop
```

The installer puts the AppImage in `~/.local/opt/hqterm-desktop/` and adds a
launcher entry (`~/.local/share/applications/hqterm.desktop`). A plain install
does this too on Linux when `$DISPLAY` or `$WAYLAND_DISPLAY` is set;
`--no-desktop` skips it.

| Keys | |
| --- | --- |
| Ctrl+Shift+T / W | new tab / close tab; Ctrl+Tab, Ctrl+PgUp/PgDn switch |
| Ctrl+Shift+D / E | split right / split down |
| Ctrl+Shift+Arrows | move between panes (or one click); drag dividers to resize |
| Ctrl+Shift+X | close pane |
| Ctrl+Shift+C / V | copy / paste |
| Ctrl+= / Ctrl+- / Ctrl+0 | zoom |

The `+` button opens a shell, the hqterm session manager, or any host from
`~/.ssh/config` and `hosts.json` (as `hqsh <host> --session main`). Splitting a
remote pane opens a new session on the same host (`main-2`, ...).

The layout (tabs, splits, each remote pane's host and session) is saved to
`~/.config/hqterm/desktop-layout.json`, and the next launch reattaches every
remote pane to its hqsh session; local panes come back as fresh shells.
Settings: `~/.config/hqterm/desktop.json`, e.g.
`{"fontFamily": "JetBrains Mono", "fontSize": 14, "theme": {"background": "#000"}, "restore": true}`.

Develop: `cd desktop && npm install && npm start` (needs bun and a C++
toolchain for node-pty); `npm run dist` builds the AppImage.

## Develop

```sh
Expand All @@ -36,7 +76,8 @@ bun run build # single binary in dist/
```

Releases: push a `v*` tag matching package.json; CI builds
`hqterm-{linux,darwin}-{amd64,arm64}` with `SHA256SUMS`.
`hqterm-{linux,darwin}-{amd64,arm64}`, `hqterm-desktop-linux-{x86_64,aarch64}.AppImage`
and `SHA256SUMS` (bump `desktop/package.json` too).

`site/index.html` is the hqterm.sh landing page; `install.sh` is served at
https://hqterm.sh/install.
Expand Down
4 changes: 4 additions & 0 deletions desktop/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
node_modules/
dist/
lib/
fonts/
Binary file added desktop/build/icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading