#!/usr/bin/env bash set -euo pipefail ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" command -v zip >/dev/null || { echo "zip is required to register the GNOME extension" >&2; exit 1; } APP_DIR="${HOME}/.local/share/jarvis-qvac" EXT_DIR="${XDG_DATA_HOME:-${HOME}/.local/share}/gnome-shell/extensions/jarvis@qvac.local" CONFIG_DIR="${HOME}/.config/jarvis" CACHE_DIR="${XDG_CACHE_HOME:-${HOME}/.cache}/jarvis/models" APP_PARENT="$(dirname "${APP_DIR}")" mkdir -p "${APP_PARENT}" "${CONFIG_DIR}" "${HOME}/.config/systemd/user" "${CACHE_DIR}" STAGING="" EXT_TMP_DIR="" cleanup_install() { rm -rf "${STAGING}" "${EXT_TMP_DIR}"; } trap cleanup_install EXIT has_bundled_bare() { [[ -f "${ROOT_DIR}/node_modules/bare-runtime-linux-x64/bin/bare" || -f "${ROOT_DIR}/node_modules/bare-runtime-linux-arm64/bin/bare" ]] } extract_tree() { local dest="$1" mkdir -p "${dest}" if has_bundled_bare; then tar --exclude='.git' --exclude='./.agents' --exclude='./.codex' --exclude='./dist' --exclude='./vendor/agent-harness/node_modules' --exclude='*/__pycache__' --exclude='*.pyc' -cf - -C "${ROOT_DIR}" . | tar -xf - -C "${dest}" else tar --exclude='.git' --exclude='./.agents' --exclude='./.codex' --exclude='./dist' --exclude='./node_modules' --exclude='*/node_modules' --exclude='*/__pycache__' --exclude='*.pyc' -cf - -C "${ROOT_DIR}" . | tar -xf - -C "${dest}" fi } PREVIOUSLY_ACTIVE=false if command -v systemctl >/dev/null; then if systemctl --user is-active --quiet jarvisd.service 2>/dev/null; then PREVIOUSLY_ACTIVE=true systemctl --user stop jarvisd.service || true fi fi if [[ -e "${APP_DIR}" || -e "${EXT_DIR}" ]]; then echo "Cleaning the previous JARVIS-QVAC install so this upgrade is a clean replacement." fi if command -v gnome-extensions >/dev/null; then gnome-extensions disable jarvis@qvac.local >/dev/null 2>&1 || true gnome-extensions uninstall jarvis@qvac.local >/dev/null 2>&1 || true fi rm -rf "${EXT_DIR}" shopt -s nullglob for leftover in "${APP_PARENT}"/jarvis-qvac.staging.*; do rm -rf "${leftover}" done shopt -u nullglob STAGING="$(mktemp -d "${APP_PARENT}/jarvis-qvac.staging.XXXXXX")" extract_tree "${STAGING}" rm -rf "${APP_DIR}" mv "${STAGING}" "${APP_DIR}" STAGING="" case "$(uname -m)" in x86_64|amd64) BARE_BIN="${APP_DIR}/node_modules/bare-runtime-linux-x64/bin/bare" ;; aarch64|arm64) BARE_BIN="${APP_DIR}/node_modules/bare-runtime-linux-arm64/bin/bare" ;; *) BARE_BIN="" ;; esac if [[ ! -x "${BARE_BIN}" ]]; then BARE_BIN="$(command -v bare || true)"; fi if [[ -z "${BARE_BIN}" || ! -x "${BARE_BIN}" ]]; then echo "The installed bundle does not contain a Bare runtime for $(uname -m). Install the official rolling bundle or build it with npm run package:bare." >&2 exit 1 fi chmod 755 "${BARE_BIN}" EXT_TMP_DIR="$(mktemp -d "${TMPDIR:-/tmp}/jarvis-extension.XXXXXX")" EXT_ZIP="${EXT_TMP_DIR}/jarvis-extension.zip" mkdir -p "${EXT_DIR}" ( cd "${ROOT_DIR}/apps/gnome-extension/jarvis@qvac.local" && zip -q -r "${EXT_ZIP}" . ) if command -v gnome-extensions >/dev/null; then if ! gnome-extensions install --force "${EXT_ZIP}"; then echo "GNOME extension registration failed; installing the files directly." >&2 cp -a "${ROOT_DIR}/apps/gnome-extension/jarvis@qvac.local/." "${EXT_DIR}/" fi else cp -a "${ROOT_DIR}/apps/gnome-extension/jarvis@qvac.local/." "${EXT_DIR}/" fi if command -v glib-compile-schemas >/dev/null && [[ -d "${EXT_DIR}/schemas" ]]; then glib-compile-schemas "${EXT_DIR}/schemas" >/dev/null fi sed "s#__JARVIS_BARE__#${BARE_BIN}#" "${ROOT_DIR}/packaging/jarvisd.service" > "${HOME}/.config/systemd/user/jarvisd.service" if [[ ! -f "${CONFIG_DIR}/qvac.config.json" ]]; then sed "s#__JARVIS_CACHE__#${CACHE_DIR}#g" "${ROOT_DIR}/packaging/qvac.config.template.json" > "${CONFIG_DIR}/qvac.config.json" fi restart_user_service() { systemctl --user daemon-reload if [[ "${1:-}" == "enable" ]]; then systemctl --user enable jarvisd.service fi systemctl --user restart jarvisd.service } if [[ "${1:-}" == "--enable" ]]; then restart_user_service enable if command -v gnome-extensions >/dev/null && gnome-extensions enable jarvis@qvac.local >/dev/null 2>&1; then echo "GNOME extension enabled." elif command -v gsettings >/dev/null && gsettings writable org.gnome.shell enabled-extensions >/dev/null 2>&1; then # A running GNOME Shell keeps its extension catalogue until the next # session. Persist the enabled state so the extension starts on login. ENABLED_EXTENSIONS="$(gsettings get org.gnome.shell enabled-extensions 2>/dev/null || printf '[]')" if [[ "${ENABLED_EXTENSIONS}" != *"jarvis@qvac.local"* ]]; then if [[ "${ENABLED_EXTENSIONS}" == "[]" ]]; then ENABLED_EXTENSIONS="['jarvis@qvac.local']" else ENABLED_EXTENSIONS="${ENABLED_EXTENSIONS%]}, 'jarvis@qvac.local']" fi gsettings set org.gnome.shell enabled-extensions "${ENABLED_EXTENSIONS}" fi echo "GNOME Shell will enable Jarvis after the next login (the current Shell session has not rescanned extensions)." else echo "GNOME Shell has not rescanned extensions; log out and back in, then run: gnome-extensions enable jarvis@qvac.local" fi elif [[ "${PREVIOUSLY_ACTIVE}" == true ]]; then restart_user_service echo "Restarted jarvisd.service with the upgraded files." fi echo "Installed JARVIS-QVAC to ${APP_DIR}" echo "Run: ${APP_DIR}/packaging/first-run.sh"