Skip to content
Open
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
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,6 @@ vendor/opencode/
# OpenCode local deps
.opencode/node_modules/
.opencode/bun.lock

# Local caches
.cache/
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,18 @@ pnpm build:ui
pnpm test:e2e
```

## Linux Build/Install Helpers

From the repo root:

```bash
./scripts/linux/build-openwork.sh
./scripts/linux/install-openwork.sh
./scripts/linux/uninstall-openwork.sh
```

`install`/`uninstall` may prompt for `sudo`.

## Troubleshooting

### Linux / Wayland (Hyprland)
Expand Down
122 changes: 122 additions & 0 deletions scripts/linux/build-openwork.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
#!/usr/bin/env bash
# Build helper for OpenWork on Linux/macOS.
# Checks required tooling and then runs `pnpm build`.
set -euo pipefail

ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
export PATH="$HOME/.local/bin:$PATH"
export NVM_DIR="${NVM_DIR:-$HOME/.nvm}"

log() { printf "[build] %s\n" "$*"; }
command_exists() { command -v "$1" >/dev/null 2>&1; }

load_nvm() {
# shellcheck disable=SC1091
if [ -s "$NVM_DIR/nvm.sh" ]; then
. "$NVM_DIR/nvm.sh"
fi
}

install_node() {
log "Installing Node via nvm..."
if [ ! -d "$NVM_DIR" ]; then
curl -fsSL https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash
fi
load_nvm
nvm install 20 --latest-npm
nvm use 20
nvm alias default 20 >/dev/null
}

ensure_node() {
if command_exists node; then
local ver major
ver="$(node -v | sed 's/^v//')"
major="${ver%%.*}"
if [ "$major" -ge 20 ]; then
return
fi
log "Found Node version v${ver} (<20) - upgrading."
else
log "Node not found."
fi
install_node
}

ensure_pnpm() {
load_nvm
log "Activating pnpm@10.27.0 via corepack..."
export COREPACK_HOME="${COREPACK_HOME:-$ROOT/.cache/corepack}"
mkdir -p "$COREPACK_HOME"
corepack enable >/dev/null 2>&1 || true
if corepack prepare pnpm@10.27.0 --activate; then
return
fi
log "corepack prepare failed - fallback: npm install --prefix \"$ROOT/.cache/npm-global\" pnpm@10.27.0"
mkdir -p "$ROOT/.cache/npm-global"
npm install --prefix "$ROOT/.cache/npm-global" pnpm@10.27.0
export PATH="$ROOT/.cache/npm-global/bin:$PATH"
}

ensure_rust() {
if ! command_exists rustup; then
log "rustup not found - installing Rust toolchain..."
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
fi
# shellcheck disable=SC1091
if [ -s "$HOME/.cargo/env" ]; then
. "$HOME/.cargo/env"
fi
}

ensure_tauri_cli() {
local required="2.0.0"
if command_exists tauri; then
local current
current="$(tauri -V | awk '{print $2}')"
if printf '%s\n%s\n' "$required" "$current" | sort -C -V 2>/dev/null; then
return
fi
log "Updating tauri-cli (found v${current}, need >= ${required})..."
else
log "tauri-cli not found - installing..."
fi
cargo install tauri-cli --locked --version "${required}"
}

ensure_opencode() {
if command_exists opencode; then
return
fi
local sidecar="$ROOT/packages/desktop/src-tauri/sidecars/opencode-x86_64-unknown-linux-gnu"
if [ -x "$sidecar" ]; then
log "Installing opencode CLI from bundled sidecar..."
mkdir -p "$HOME/.local/bin"
cp "$sidecar" "$HOME/.local/bin/opencode"
chmod +x "$HOME/.local/bin/opencode"
else
log "Warning: opencode CLI missing and sidecar not found. Install manually: https://github.com/anomalyco/opencode/releases"
fi
}

main() {
if [ "$(uname -s)" != "Linux" ] && [ "$(uname -s)" != "Darwin" ]; then
log "Warning: this script primarily targets Linux/macOS."
fi

ensure_node
ensure_pnpm
ensure_rust
ensure_tauri_cli
ensure_opencode

log "Installing JS dependencies (pnpm install)..."
cd "$ROOT"
pnpm install

log "Starting build (pnpm build)..."
pnpm build
log "Build finished. Artifacts: packages/desktop/src-tauri/target/release/bundle/"
}

main "$@"
86 changes: 86 additions & 0 deletions scripts/linux/install-openwork.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
#!/usr/bin/env bash
# Install helper that uses artifacts from target/release/bundle.
set -euo pipefail

ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
BUNDLE="$ROOT/packages/desktop/src-tauri/target/release/bundle"

log() { printf "[install] %s\n" "$*"; }
die() { printf "[install] ERROR: %s\n" "$*" >&2; exit 1; }
latest_file() {
local pattern="$1"
ls -t ${pattern} 2>/dev/null | head -n1 || true
}

install_linux() {
local deb appimage
deb="$(latest_file "$BUNDLE/deb/*.deb")"
appimage="$(latest_file "$BUNDLE/appimage/*.AppImage")"

if [ -n "$deb" ] && command -v dpkg >/dev/null 2>&1; then
log "Installing Debian package: $deb"
sudo dpkg -i "$deb"
log "Done. OpenWork should now appear in your application menu."
return
fi

if [ -n "$appimage" ]; then
log "No usable .deb found - falling back to AppImage: $appimage"
mkdir -p "$HOME/.local/bin"
cp "$appimage" "$HOME/.local/bin/openwork.AppImage"
chmod +x "$HOME/.local/bin/openwork.AppImage"
cat > "$HOME/.local/bin/openwork" <<'EOF'
#!/usr/bin/env bash
exec "$(dirname "$0")/openwork.AppImage" "$@"
EOF
chmod +x "$HOME/.local/bin/openwork"
log "AppImage installed to $HOME/.local/bin. Ensure $HOME/.local/bin is on PATH (for example via ~/.profile). Launch with: openwork"
return
fi

die "No Linux artifacts found. Run scripts/linux/build-openwork.sh first."
}

install_macos() {
local dmg
dmg="$(latest_file "$BUNDLE/macos/OpenWork_*.dmg")"
[ -n "$dmg" ] || die "No DMG found. Run the build script first."

local mnt="/Volumes/OpenWorkInstaller"
log "Mounting DMG: $dmg"
hdiutil attach "$dmg" -mountpoint "$mnt" -quiet
trap 'hdiutil detach "$mnt" -quiet || true' EXIT

if [ -d "$mnt/OpenWork.app" ]; then
log "Copying to /Applications..."
rm -rf /Applications/OpenWork.app
cp -R "$mnt/OpenWork.app" /Applications/
else
die "OpenWork.app not found inside the DMG."
fi

hdiutil detach "$mnt" -quiet
trap - EXIT
log "Installed. Launch OpenWork from /Applications."
}

install_windows() {
local msi exe
msi="$(latest_file "$BUNDLE/msi/*.msi")"
exe="$(latest_file "$BUNDLE/nsis/*setup*.exe")"
if [ -z "$msi" ] && [ -z "$exe" ]; then
die "No Windows installers found. Run the build script first."
fi
log "Please run the installer manually (double-click): ${msi:-$exe}"
}

main() {
case "$(uname -s)" in
Linux) install_linux ;;
Darwin) install_macos ;;
MINGW*|MSYS*|CYGWIN*|Windows_NT) install_windows ;;
*) die "Unsupported OS: $(uname -s)" ;;
esac
}

main "$@"
91 changes: 91 additions & 0 deletions scripts/linux/uninstall-openwork.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
#!/usr/bin/env bash
# Uninstall helper for OpenWork artifacts and packages.
set -euo pipefail

ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
BUNDLE="$ROOT/packages/desktop/src-tauri/target/release/bundle"

log() { printf "[uninstall] %s\n" "$*"; }
die() { printf "[uninstall] ERROR: %s\n" "$*" >&2; exit 1; }
latest_file() {
local pattern="$1"
ls -t ${pattern} 2>/dev/null | head -n1 || true
}

detect_deb_package_name() {
local control_file pkg
control_file="$(latest_file "$BUNDLE/deb/"*/control/control)"
if [ -n "$control_file" ]; then
pkg="$(awk -F': ' '/^Package:/{print $2; exit}' "$control_file")"
if [ -n "$pkg" ]; then
printf "%s" "$pkg"
return
fi
fi
# Fallback for older builds or missing bundle metadata.
printf "open-work"
}

remove_appimage_install() {
local removed=0
if [ -f "$HOME/.local/bin/openwork" ]; then
rm -f "$HOME/.local/bin/openwork"
removed=1
fi
if [ -f "$HOME/.local/bin/openwork.AppImage" ]; then
rm -f "$HOME/.local/bin/openwork.AppImage"
removed=1
fi
if [ "$removed" -eq 1 ]; then
log "Removed AppImage launchers from $HOME/.local/bin."
fi
}

uninstall_linux() {
command -v dpkg >/dev/null 2>&1 || die "dpkg not found."

local pkg="open-work"
pkg="$(detect_deb_package_name)"
log "Detected Debian package name: $pkg"

if dpkg -s "$pkg" >/dev/null 2>&1; then
if command -v apt-get >/dev/null 2>&1; then
log "Removing package via apt-get..."
sudo apt-get remove -y "$pkg" || sudo dpkg -r "$pkg"
else
log "Removing package via dpkg..."
sudo dpkg -r "$pkg"
fi
log "Package removed: $pkg"
else
log "Package not installed: $pkg"
fi

remove_appimage_install
log "Linux uninstall complete."
}

uninstall_macos() {
if [ -d "/Applications/OpenWork.app" ]; then
log "Removing /Applications/OpenWork.app..."
rm -rf /Applications/OpenWork.app
log "Removed /Applications/OpenWork.app"
else
log "OpenWork.app not found in /Applications."
fi
}

uninstall_windows() {
log "Please uninstall OpenWork from Settings > Apps on Windows."
}

main() {
case "$(uname -s)" in
Linux) uninstall_linux ;;
Darwin) uninstall_macos ;;
MINGW*|MSYS*|CYGWIN*|Windows_NT) uninstall_windows ;;
*) die "Unsupported OS: $(uname -s)" ;;
esac
}

main "$@"