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
114 changes: 114 additions & 0 deletions .github/workflows/desktop-prerelease.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
name: Desktop Pre-release

# Every push that touches desktop/ on the dev branch builds the installers and publishes a
# PRE-RELEASE GitHub Release (marked prerelease: true). The admin.spot-suite.com "ShellDeck
# Desktop" tab lists these under "Pre-release builds" so dev versions can be tried before a
# stable `desktop-v*` tag is cut. Old pre-releases are pruned (keep the newest 5).

on:
push:
branches:
- master
- feat/shelldeck-desktop
paths:
- "desktop/**"
- ".github/workflows/desktop-prerelease.yml"

permissions:
contents: write

env:
RELEASE_CONFIG: '{"bundle":{"createUpdaterArtifacts":false}}'

jobs:
prep:
runs-on: ubuntu-latest
outputs:
tag: ${{ steps.v.outputs.tag }}
steps:
- uses: actions/checkout@v4
- id: v
run: |
VERSION="$(node -p "require('./desktop/package.json').version")"
echo "tag=desktop-v${VERSION}-dev.${{ github.run_number }}" >> "$GITHUB_OUTPUT"

linux:
needs: prep
runs-on: ubuntu-latest
defaults:
run:
working-directory: desktop
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "24"
cache: npm
cache-dependency-path: desktop/package-lock.json
- uses: dtolnay/rust-toolchain@stable
- name: Install Tauri Linux dependencies
run: |
sudo apt-get update
sudo apt-get install -y \
build-essential curl file wget \
libayatana-appindicator3-dev \
librsvg2-dev libssl-dev libwebkit2gtk-4.1-dev
- name: Install desktop dependencies
run: npm ci
- name: Build AppImage
run: npm run tauri build -- --bundles appimage --config "$RELEASE_CONFIG"
- name: Publish Linux pre-release bundle
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ needs.prep.outputs.tag }}
name: ShellDeck Desktop ${{ needs.prep.outputs.tag }}
prerelease: true
generate_release_notes: true
fail_on_unmatched_files: true
files: desktop/src-tauri/target/release/bundle/appimage/*.AppImage

windows:
needs: prep
runs-on: windows-latest
defaults:
run:
working-directory: desktop
shell: bash
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "24"
cache: npm
cache-dependency-path: desktop/package-lock.json
- uses: dtolnay/rust-toolchain@stable
- name: Install desktop dependencies
run: npm ci
- name: Build NSIS installer
run: npm run tauri build -- --bundles nsis --config "$RELEASE_CONFIG"
- name: Publish Windows pre-release bundle
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ needs.prep.outputs.tag }}
name: ShellDeck Desktop ${{ needs.prep.outputs.tag }}
prerelease: true
generate_release_notes: true
fail_on_unmatched_files: true
files: desktop/src-tauri/target/release/bundle/nsis/*.exe

prune:
needs: [linux, windows]
runs-on: ubuntu-latest
env:
GH_TOKEN: ${{ github.token }}
steps:
- name: Keep only the 5 newest dev pre-releases
run: |
gh release list --repo "$GITHUB_REPOSITORY" --limit 100 \
--json tagName,isPrerelease,createdAt \
--jq '[.[] | select(.isPrerelease and (.tagName | test("^desktop-v.*-dev\\.")))] | sort_by(.createdAt) | reverse | .[5:] | .[].tagName' \
| while read -r tag; do
[ -n "$tag" ] || continue
echo "Pruning old pre-release $tag"
gh release delete "$tag" --repo "$GITHUB_REPOSITORY" --yes --cleanup-tag
done
87 changes: 87 additions & 0 deletions .github/workflows/desktop-release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
name: Desktop Release

# On a `desktop-v*` tag, build the Windows .exe + Linux AppImage and publish them as a
# GitHub Release with auto-generated notes (changelog from merged PRs/commits since the last
# tag). This is the distribution source the admin.spot-suite.com "ShellDeck Desktop" tab reads.
#
# v1 is unsigned (no secrets needed): updater artifacts are disabled, so there is no auto-update
# yet and Windows SmartScreen warns on first run. Code signing + a Tauri updater feed are a
# documented fast-follow (see desktop/STATUS.md).

on:
push:
tags:
- "desktop-v*"

permissions:
contents: write

# Unsigned build — disable updater artifacts so no signing key is required.
env:
RELEASE_CONFIG: '{"bundle":{"createUpdaterArtifacts":false}}'

jobs:
linux:
name: Linux AppImage
runs-on: ubuntu-latest
defaults:
run:
working-directory: desktop
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "24"
cache: npm
cache-dependency-path: desktop/package-lock.json
- uses: dtolnay/rust-toolchain@stable
- name: Install Tauri Linux dependencies
run: |
sudo apt-get update
sudo apt-get install -y \
build-essential curl file wget \
libayatana-appindicator3-dev \
librsvg2-dev libssl-dev libwebkit2gtk-4.1-dev
- name: Install desktop dependencies
run: npm ci
- name: Build AppImage + deb
run: npm run tauri build -- --bundles appimage,deb --config "$RELEASE_CONFIG"
- name: Publish Linux bundles to the GitHub Release
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ github.ref_name }}
name: ShellDeck Desktop ${{ github.ref_name }}
generate_release_notes: true
fail_on_unmatched_files: true
files: |
desktop/src-tauri/target/release/bundle/appimage/*.AppImage
desktop/src-tauri/target/release/bundle/deb/*.deb

windows:
name: Windows .exe
runs-on: windows-latest
defaults:
run:
working-directory: desktop
shell: bash
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "24"
cache: npm
cache-dependency-path: desktop/package-lock.json
- uses: dtolnay/rust-toolchain@stable
- name: Install desktop dependencies
run: npm ci
- name: Build NSIS installer
run: npm run tauri build -- --bundles nsis --config "$RELEASE_CONFIG"
- name: Publish Windows installer to the GitHub Release
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ github.ref_name }}
name: ShellDeck Desktop ${{ github.ref_name }}
generate_release_notes: true
fail_on_unmatched_files: true
files: |
desktop/src-tauri/target/release/bundle/nsis/*.exe
5 changes: 5 additions & 0 deletions desktop/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
node_modules
dist
src-tauri/target
*.log

76 changes: 76 additions & 0 deletions desktop/BUILD.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
# ShellDeck Desktop Build Notes

ShellDeck Desktop is a Tauri v2 thin client. It does not bundle or start the ShellDeck server; it opens a user-configured server URL in a persistent desktop webview.

## Prerequisites

- Node.js 22+ and npm.
- Rust stable.
- Linux GUI build packages when building locally: `libwebkit2gtk-4.1-dev`, `build-essential`, `libssl-dev`, `libayatana-appindicator3-dev`, `librsvg2-dev`, `curl`, `wget`, and `file`.
- No local secret files are required for unsigned local checks.

## Install and Check Locally

```sh
cd desktop
npm ci
npm run build
```

If the Linux WebKitGTK development package is installed, also run:

```sh
cd desktop/src-tauri
cargo check
```

To build local Linux bundles:

```sh
cd desktop
npm run tauri build -- --bundles appimage,deb
```

## Updater Keypair

Generate the Tauri updater keypair once:

```sh
cd desktop
npm run tauri signer generate
```

Keep the private key out of the repo. Put only the public key in `src-tauri/tauri.conf.json`, replacing `REPLACE_WITH_TAURI_UPDATER_PUBKEY`.

Store the private key and password in GitHub Actions secrets:

- `TAURI_SIGNING_PRIVATE_KEY`
- `TAURI_SIGNING_PRIVATE_KEY_PASSWORD`

## Release Secrets

The release workflow also expects Cloudflare R2 credentials by secret name:

- `CLOUDFLARE_ACCOUNT_ID`
- `CLOUDFLARE_API_TOKEN`
- `SHELLDECK_R2_BUCKET`

The R2 bucket must serve `https://dl.shelldeck.app/desktop/...` through its custom domain. No R2 credential value belongs in this repo.

## Cut a Release

1. Update the desktop version in `desktop/package.json`, `desktop/src-tauri/Cargo.toml`, and `desktop/src-tauri/tauri.conf.json`.
2. Make sure the updater public key placeholder has been replaced with the generated public key.
3. Commit the version change.
4. Tag the release:

```sh
git tag desktop-vX.Y.Z
git push origin feat/shelldeck-desktop
git push origin desktop-vX.Y.Z
Comment on lines +69 to +70
```

The tag triggers `.github/workflows/desktop-release.yml`. It builds Linux AppImage and `.deb` bundles on `ubuntu-latest`, builds the Windows NSIS installer on `windows-latest`, signs updater artifacts with the Tauri signing secrets, writes per-target `latest.json`, uploads artifacts to R2, and attaches them to the GitHub Release.

Windows code signing is intentionally skipped in v1, so Windows may show a SmartScreen warning until Authenticode signing is added.

32 changes: 32 additions & 0 deletions desktop/STATUS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# ShellDeck Desktop Status

## Built

- Added `desktop/`, a Tauri v2 thin client named ShellDeck.
- Added a first-run/settings screen that stores a ShellDeck server URL in localStorage.
- Added a Rust reachability check for the configured server URL before navigation.
- Added a connection-error screen with Retry and Edit server URL actions.
- Added native window state persistence, tray actions, single-instance focus behavior, and updater wiring.
- Added `.github/workflows/desktop-release.yml` for tag-based Linux and Windows desktop releases.
- Added `site/`, a static Cloudflare Pages landing page with current-version download buttons backed by `latest.json`.

## Verified

- `npm install` in `desktop/` completed with no vulnerabilities.
- `npm run build` in `desktop/` completed successfully.
- `npm run latest-json` generated a valid test updater manifest from a throwaway signature file.
- `git diff --check` completed with no whitespace errors.
- `cargo fmt --check` completed successfully.
- `npm run tauri info` parsed the Tauri app and confirmed WebKitGTK 4.1 is the missing local prerequisite.
- Playwright loaded the static site at desktop and 390px widths: no console warnings/errors after localhost manifest fetches were disabled, and no horizontal overflow was detected.
- Playwright loaded the desktop settings screen through Vite at desktop and 390px widths: no console warnings/errors and no horizontal overflow was detected.
- `cargo check` in `desktop/src-tauri` could not complete on this machine because WebKitGTK 4.1 development packages are not installed locally.

## Remaining Manual Steps

- Generate the Tauri updater keypair with `npm run tauri signer generate`.
- Replace `REPLACE_WITH_TAURI_UPDATER_PUBKEY` in `desktop/src-tauri/tauri.conf.json` with the generated public key.
- Add GitHub secrets: `TAURI_SIGNING_PRIVATE_KEY`, `TAURI_SIGNING_PRIVATE_KEY_PASSWORD`, `CLOUDFLARE_ACCOUNT_ID`, `CLOUDFLARE_API_TOKEN`, and `SHELLDECK_R2_BUCKET`.
- Confirm `dl.shelldeck.app` serves the R2 bucket path used by the workflow.
- Replace `site/screenshot-*.png` placeholders with real screenshots.
- Cut the first release with `git tag desktop-vX.Y.Z` and push the tag.
13 changes: 13 additions & 0 deletions desktop/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>ShellDeck</title>
<link rel="icon" href="/favicon.png" />
<script type="module" src="/src/main.ts"></script>
</head>
<body>
<main id="app" class="shell"></main>
</body>
</html>
Loading
Loading