summaryrefslogtreecommitdiffhomepage
path: root/packaging
diff options
context:
space:
mode:
authorAdam Malczewski <[email protected]>2026-05-22 16:19:35 +0900
committerAdam Malczewski <[email protected]>2026-05-22 16:19:35 +0900
commit45a4890031192f4e7409443f98e824dad17ba175 (patch)
treea28e1b0618f682476b0b57ba70e8ba26a1939a49 /packaging
parent9ecaabd87c0e51b8a7408dabb0133a9344586859 (diff)
downloaddispatch-45a4890031192f4e7409443f98e824dad17ba175.tar.gz
dispatch-45a4890031192f4e7409443f98e824dad17ba175.zip
feat: Arch Linux packaging with Electron frontend, systemd backend service, and Windows exe build
- Add Electron wrapper (main.cjs, preload.cjs) for desktop frontend - Add systemd service unit, env config, and sysusers for backend API - Add PKGBUILD and .install for Arch package (makepkg -si) - Add desktop entry, SVG/PNG icon, and wrapper scripts - Add bin/build-pkg, bin/install-pkg, bin/windows-pkg scripts - Make API port configurable via PORT env var (default 3000, prod 18390) - Add electron-builder config for Windows exe cross-compilation - Set vite base to './' for Electron file:// loading
Diffstat (limited to 'packaging')
-rw-r--r--packaging/PKGBUILD131
-rwxr-xr-xpackaging/dispatch-api-wrapper.sh32
-rw-r--r--packaging/dispatch-api.conf31
-rw-r--r--packaging/dispatch-api.service33
-rwxr-xr-xpackaging/dispatch-electron-wrapper.sh2
-rw-r--r--packaging/dispatch.desktop9
-rw-r--r--packaging/dispatch.install16
-rw-r--r--packaging/dispatch.pngbin0 -> 10192 bytes
-rw-r--r--packaging/dispatch.svg24
9 files changed, 278 insertions, 0 deletions
diff --git a/packaging/PKGBUILD b/packaging/PKGBUILD
new file mode 100644
index 0000000..57e7e28
--- /dev/null
+++ b/packaging/PKGBUILD
@@ -0,0 +1,131 @@
+# Maintainer: dispatch
+pkgname=dispatch
+pkgver=0.0.1
+pkgrel=1
+pkgdesc='AI Agent Dispatch Interface'
+arch=('x86_64')
+url='https://github.com/anomalyco/dispatch'
+license=('MIT')
+depends=('electron' 'bun')
+makedepends=()
+install=dispatch.install
+backup=('etc/dispatch/dispatch-api.conf')
+source=(
+ 'dispatch-api.service'
+ 'dispatch-api.conf'
+ 'dispatch-electron-wrapper.sh'
+ 'dispatch-api-wrapper.sh'
+ 'dispatch.desktop'
+ 'dispatch.svg'
+)
+sha256sums=('SKIP' 'SKIP' 'SKIP' 'SKIP' 'SKIP' 'SKIP')
+
+_projectdir="${startdir}/.."
+
+prepare() {
+ mkdir -p "${srcdir}/dispatch-${pkgver}"
+ # Copy project files into the src build directory (use -a to preserve symlinks)
+ cp -a \
+ "${_projectdir}/packages" \
+ "${_projectdir}/package.json" \
+ "${_projectdir}/bun.lock" \
+ "${_projectdir}/tsconfig.base.json" \
+ "${srcdir}/dispatch-${pkgver}/"
+
+ # Copy dispatch.toml if it exists
+ if [ -f "${_projectdir}/dispatch.toml" ]; then
+ cp "${_projectdir}/dispatch.toml" "${srcdir}/dispatch-${pkgver}/"
+ fi
+}
+
+build() {
+ cd "${srcdir}/dispatch-${pkgver}"
+
+ # Install all deps (including devDependencies needed for vite build)
+ bun install --frozen-lockfile
+
+ # Build the frontend with production API port
+ VITE_API_URL="http://localhost:18390" bun run --cwd packages/frontend build
+
+ # Reinstall with production only to slim down node_modules for packaging
+ rm -rf node_modules
+ bun install --frozen-lockfile --production
+}
+
+package() {
+ cd "${srcdir}/dispatch-${pkgver}"
+
+ local optdir="${pkgdir}/opt/dispatch"
+
+ # --- Application files ---
+
+ # API package (full source)
+ install -dm755 "${optdir}/packages/api"
+ cp -a packages/api/. "${optdir}/packages/api/"
+
+ # Core package (full source)
+ install -dm755 "${optdir}/packages/core"
+ cp -a packages/core/. "${optdir}/packages/core/"
+
+ # Frontend: built dist only
+ install -dm755 "${optdir}/packages/frontend/dist"
+ cp -a packages/frontend/dist/. "${optdir}/packages/frontend/dist/"
+
+ # Frontend: electron launcher files
+ install -dm755 "${optdir}/packages/frontend/electron"
+ cp -a packages/frontend/electron/. "${optdir}/packages/frontend/electron/"
+
+ # Frontend: package.json (needed for workspace resolution)
+ install -Dm644 packages/frontend/package.json "${optdir}/packages/frontend/package.json"
+
+ # Runtime node_modules (preserve symlinks for bun workspaces)
+ install -dm755 "${optdir}/node_modules"
+ cp -a node_modules/. "${optdir}/node_modules/"
+
+ # Root manifest and lockfile
+ install -Dm644 package.json "${optdir}/package.json"
+ install -Dm644 bun.lock "${optdir}/bun.lock"
+
+ # Default config (if present)
+ if [ -f dispatch.toml ]; then
+ install -Dm644 dispatch.toml "${optdir}/dispatch.toml"
+ fi
+
+ # --- systemd service ---
+ install -Dm644 \
+ "${srcdir}/dispatch-api.service" \
+ "${pkgdir}/usr/lib/systemd/system/dispatch-api.service"
+
+ # --- Environment config (preserved across upgrades via backup=()) ---
+ install -Dm644 \
+ "${srcdir}/dispatch-api.conf" \
+ "${pkgdir}/etc/dispatch/dispatch-api.conf"
+
+ # --- Wrapper scripts ---
+ install -Dm755 \
+ "${srcdir}/dispatch-electron-wrapper.sh" \
+ "${pkgdir}/usr/bin/dispatch"
+
+ install -Dm755 \
+ "${srcdir}/dispatch-api-wrapper.sh" \
+ "${pkgdir}/usr/bin/dispatch-api"
+
+ # --- Desktop integration ---
+ install -Dm644 \
+ "${srcdir}/dispatch.desktop" \
+ "${pkgdir}/usr/share/applications/dispatch.desktop"
+
+ install -Dm644 \
+ "${srcdir}/dispatch.svg" \
+ "${pkgdir}/usr/share/icons/hicolor/scalable/apps/dispatch.svg"
+
+ # --- sysusers: create the 'dispatch' system user ---
+ install -Dm644 /dev/null "${pkgdir}/usr/lib/sysusers.d/dispatch.conf"
+ echo 'u dispatch - "Dispatch API" /var/lib/dispatch' > "${pkgdir}/usr/lib/sysusers.d/dispatch.conf"
+
+ # --- License ---
+ if [ -f "${_projectdir}/LICENSE" ]; then
+ install -Dm644 "${_projectdir}/LICENSE" \
+ "${pkgdir}/usr/share/licenses/${pkgname}/LICENSE"
+ fi
+}
diff --git a/packaging/dispatch-api-wrapper.sh b/packaging/dispatch-api-wrapper.sh
new file mode 100755
index 0000000..d8c656b
--- /dev/null
+++ b/packaging/dispatch-api-wrapper.sh
@@ -0,0 +1,32 @@
+#!/bin/bash
+# dispatch-api-wrapper.sh
+# Wrapper script for running the Dispatch API outside of systemd.
+# Install to /usr/bin/dispatch-api (chmod 755).
+#
+# Usage:
+# dispatch-api # runs the server, inheriting the current environment
+# dispatch-api --help # passes flags through to bun
+
+set -euo pipefail
+
+DISPATCH_CONF="/etc/dispatch/dispatch-api.conf"
+DISPATCH_DIR="/opt/dispatch"
+BUN="/usr/bin/bun"
+ENTRY_POINT="packages/api/src/index.ts"
+
+# Source the environment file if it exists
+if [[ -f "$DISPATCH_CONF" ]]; then
+ # Export every variable defined in the conf file so child processes see them.
+ # Lines starting with '#' and blank lines are skipped automatically by bash's
+ # 'source' builtin.
+ set -o allexport
+ # shellcheck source=/etc/dispatch/dispatch-api.conf
+ source "$DISPATCH_CONF"
+ set +o allexport
+fi
+
+# Change to the application directory
+cd "$DISPATCH_DIR"
+
+# Hand off to bun — exec replaces this process so signals are forwarded correctly
+exec "$BUN" "$ENTRY_POINT" "$@"
diff --git a/packaging/dispatch-api.conf b/packaging/dispatch-api.conf
new file mode 100644
index 0000000..9824e16
--- /dev/null
+++ b/packaging/dispatch-api.conf
@@ -0,0 +1,31 @@
+# /etc/dispatch/dispatch-api.conf
+# Environment configuration for the Dispatch API service.
+# This file is sourced by systemd (via EnvironmentFile=) and by the
+# dispatch-api-wrapper.sh script for manual invocation.
+#
+# Lines beginning with '#' are comments and are ignored.
+# Syntax: KEY=value (no spaces around '=', no 'export' keyword needed for systemd)
+
+# ---------------------------------------------------------------------------
+# LLM / AI provider
+# ---------------------------------------------------------------------------
+
+# API key used by the backend to call the OpenCode (or compatible) LLM API.
+OPENCODE_API_KEY=
+
+# ---------------------------------------------------------------------------
+# Runtime environment
+# ---------------------------------------------------------------------------
+
+# Set to "production" for live deployments.
+NODE_ENV=production
+
+# ---------------------------------------------------------------------------
+# Server
+# ---------------------------------------------------------------------------
+
+# Port the API listens on (default: 3000).
+PORT=18390
+
+# Hostname/address to bind to (default: 0.0.0.0).
+# HOST=0.0.0.0
diff --git a/packaging/dispatch-api.service b/packaging/dispatch-api.service
new file mode 100644
index 0000000..ccbb727
--- /dev/null
+++ b/packaging/dispatch-api.service
@@ -0,0 +1,33 @@
+[Unit]
+Description=Dispatch API Backend
+After=network-online.target
+Wants=network-online.target
+
+[Service]
+Type=simple
+User=dispatch
+Group=dispatch
+WorkingDirectory=/opt/dispatch
+ExecStart=/usr/bin/bun packages/api/src/index.ts
+EnvironmentFile=-/etc/dispatch/dispatch-api.conf
+Restart=on-failure
+RestartSec=5
+StandardOutput=journal
+StandardError=journal
+
+# Data directory: systemd creates /var/lib/dispatch owned by dispatch:dispatch
+StateDirectory=dispatch
+
+# Tell the app to store its SQLite DB under /var/lib/dispatch/
+Environment=XDG_DATA_HOME=/var/lib
+
+# Security hardening
+ProtectSystem=strict
+ProtectHome=true
+NoNewPrivileges=true
+PrivateTmp=true
+PrivateDevices=true
+RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX
+
+[Install]
+WantedBy=multi-user.target
diff --git a/packaging/dispatch-electron-wrapper.sh b/packaging/dispatch-electron-wrapper.sh
new file mode 100755
index 0000000..df24713
--- /dev/null
+++ b/packaging/dispatch-electron-wrapper.sh
@@ -0,0 +1,2 @@
+#!/bin/bash
+exec /usr/bin/electron --name="Dispatch" /opt/dispatch/packages/frontend/electron/main.cjs "$@"
diff --git a/packaging/dispatch.desktop b/packaging/dispatch.desktop
new file mode 100644
index 0000000..0ed44af
--- /dev/null
+++ b/packaging/dispatch.desktop
@@ -0,0 +1,9 @@
+[Desktop Entry]
+Name=Dispatch
+Comment=AI Agent Dispatch Interface
+Exec=/usr/bin/dispatch %U
+Icon=dispatch
+Terminal=false
+Type=Application
+Categories=Development;Utility;
+StartupWMClass=Dispatch
diff --git a/packaging/dispatch.install b/packaging/dispatch.install
new file mode 100644
index 0000000..e6db694
--- /dev/null
+++ b/packaging/dispatch.install
@@ -0,0 +1,16 @@
+post_install() {
+ echo ""
+ echo "==> Dispatch has been installed."
+ echo " Edit /etc/dispatch/dispatch-api.conf to configure the API."
+ echo " Then enable and start the service:"
+ echo " systemctl enable --now dispatch-api"
+ echo ""
+}
+
+post_upgrade() {
+ echo ""
+ echo "==> Dispatch has been upgraded."
+ echo " You may need to restart the service:"
+ echo " systemctl restart dispatch-api"
+ echo ""
+}
diff --git a/packaging/dispatch.png b/packaging/dispatch.png
new file mode 100644
index 0000000..84d743a
--- /dev/null
+++ b/packaging/dispatch.png
Binary files differ
diff --git a/packaging/dispatch.svg b/packaging/dispatch.svg
new file mode 100644
index 0000000..2aae97f
--- /dev/null
+++ b/packaging/dispatch.svg
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" width="64" height="64">
+ <defs>
+ <linearGradient id="bg" x1="0%" y1="0%" x2="100%" y2="100%">
+ <stop offset="0%" style="stop-color:#5b6af0"/>
+ <stop offset="100%" style="stop-color:#9b59f7"/>
+ </linearGradient>
+ <linearGradient id="arrow" x1="0%" y1="0%" x2="100%" y2="100%">
+ <stop offset="0%" style="stop-color:#ffffff;stop-opacity:1"/>
+ <stop offset="100%" style="stop-color:#e0d8ff;stop-opacity:1"/>
+ </linearGradient>
+ </defs>
+
+ <!-- Rounded square background -->
+ <rect x="2" y="2" width="60" height="60" rx="14" ry="14" fill="url(#bg)"/>
+
+ <!-- Send/dispatch arrow icon: a paper-plane style arrow pointing upper-right -->
+ <!-- Main arrow body -->
+ <polygon points="10,50 54,10 38,32" fill="url(#arrow)" opacity="0.95"/>
+ <!-- Arrow tail fill -->
+ <polygon points="10,50 28,36 22,54" fill="url(#arrow)" opacity="0.75"/>
+ <!-- Subtle highlight line -->
+ <line x1="54" y1="10" x2="28" y2="36" stroke="white" stroke-width="1.5" stroke-linecap="round" opacity="0.5"/>
+</svg>