Files
NexusOS/assets/themes/KDE/install-plasma.sh
T
janvanwan 42eaed647a feat: sync with upstream — v1.2.0, in-app updates, Projects, modules
Brings the public tree back in line with the development repo after several
weeks of drift caused by a stale publish include list.

New:
- In-app update path: GET /update/check compares the checkout against
  origin/main and POST /update/apply runs `ncp upgrade` detached (pull,
  rebuild, restart). The sidebar shows the version, checks on click, and
  offers an "update available" pill.
- Projects: a project workspace groups chats and RAG documents, with
  per-project instructions and document retrieval scoped to the active
  project. Replaces the standalone Documents page.
- modules/: auto-discovered feature plugins (mail, network) with their
  frontend counterparts and tests.
- Memory curation runs in-process (synapse/memory/curator.py) on the chat
  model when a conversation goes idle. The separate memory service on :8001
  is gone, along with the launcher lines that started it.

Also: the KDE theme, panel and Promethean terminal assets, the full test
suite, and VERSION 1.2.0.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-08-25 09:13:55 -05:00

305 lines
14 KiB
Bash

#!/usr/bin/env bash
# NexusOS KDE Plasma theme installer — idempotent, safe to re-run.
# Equivalent of assets/themes/install-theme.sh but for KDE.
#
# Usage:
# assets/themes/KDE/install-plasma.sh [--no-sddm]
#
# --no-sddm skip the SDDM step (requires sudo) — useful for live testing
set -euo pipefail
KDE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO="$(cd "$KDE/../../.." && pwd)"
NO_SDDM=0
FORCE_PANEL=0
for arg in "$@"; do
[[ "$arg" == "--no-sddm" ]] && NO_SDDM=1
[[ "$arg" == "--panel" ]] && FORCE_PANEL=1
done
echo "NexusOS KDE installer — repo: $REPO"
# ── 1. Create target directories ────────────────────────────────────────
mkdir -p \
~/.local/share/aurorae/themes \
~/.local/share/plasma/desktoptheme \
~/.local/share/color-schemes \
~/.local/share/konsole \
~/.config/Kvantum
# ── 2. Symlink theme directories (update automatically on git pull) ──────
ln -sfn "$KDE/aurorae/NexusOS" ~/.local/share/aurorae/themes/NexusOS
ln -sfn "$KDE/plasma/NexusOS" ~/.local/share/plasma/desktoptheme/NexusOS
ln -sfn "$KDE/kvantum/NexusOS" ~/.config/Kvantum/NexusOS
echo " [ok] theme symlinks"
# ── 3. Copy files that need to be in specific locations (not symlinks) ───
cp -f "$KDE/plasma/NexusOS/NexusOS.colors" ~/.local/share/color-schemes/
cp -f "$KDE/konsole/NexusOS.colorscheme" ~/.local/share/konsole/
cp -f "$KDE/konsole/NexusOS-Promethean.colorscheme" ~/.local/share/konsole/
cp -f "$KDE/konsole/Promethean.profile" ~/.local/share/konsole/
echo " [ok] color scheme + konsole files"
# ── 4. KDE color scheme ──────────────────────────────────────────────────
if command -v plasma-apply-colorscheme &>/dev/null; then
plasma-apply-colorscheme NexusOS 2>/dev/null && echo " [ok] color scheme applied"
else
echo " [skip] plasma-apply-colorscheme not found — apply color scheme manually"
fi
# ── 5. Kvantum ───────────────────────────────────────────────────────────
if command -v kvantummanager &>/dev/null; then
kvantummanager --set NexusOS 2>/dev/null && echo " [ok] Kvantum set to NexusOS"
else
echo " [skip] kvantummanager not found — install qt5-style-kvantum and run: kvantummanager --set NexusOS"
fi
# ── 6. KWin Aurorae decoration ───────────────────────────────────────────
if command -v kwriteconfig5 &>/dev/null; then
kwriteconfig5 --file kwinrc \
--group "org.kde.kdecoration2" --key library "org.kde.kwin.aurorae"
kwriteconfig5 --file kwinrc \
--group "org.kde.kdecoration2" --key theme "__aurorae__svg__NexusOS"
# Buttons on the right: minimize, maximize, close (I=minimize, A=maximize, X=close)
kwriteconfig5 --file kwinrc \
--group "org.kde.kdecoration2" --key ButtonsOnLeft ""
kwriteconfig5 --file kwinrc \
--group "org.kde.kdecoration2" --key ButtonsOnRight "IAX"
echo " [ok] KWin decoration: Aurorae NexusOS, buttons right"
else
echo " [skip] kwriteconfig5 not found — configure KWin decoration manually"
fi
# ── 7. Plasma shell theme ────────────────────────────────────────────────
if command -v plasma-apply-desktoptheme &>/dev/null; then
plasma-apply-desktoptheme NexusOS 2>/dev/null && echo " [ok] Plasma shell theme: NexusOS"
else
echo " [skip] plasma-apply-desktoptheme not found — apply desktop theme manually"
fi
# ── 8. Lock screen ───────────────────────────────────────────────────────
# Plasma 5.27 draws the lock screen from a look-and-feel package's
# contents/lockscreen, and [Greeter]Theme names that PACKAGE. The old value here
# ("NexusOS") was not a look-and-feel id, so it silently fell back to Breeze.
# The standalone kscreenlocker theme that value referred to targeted an earlier
# kscreenlocker API that 5.27 no longer loads, and has been deleted.
#
# Breeze's lock UI is deliberately kept rather than replaced: a lock screen that
# fails to load is one you cannot get back through. Only the wallpaper is ours,
# which is what carries the brushed-metal look.
if command -v kwriteconfig5 &>/dev/null; then
kwriteconfig5 --file kscreenlockerrc --group Greeter --key Theme org.kde.breeze.desktop
LOCK_BG="$KDE/sddm/NexusOS-QML/assets/background.png"
if [[ -f "$LOCK_BG" ]]; then
kwriteconfig5 --file kscreenlockerrc \
--group Greeter --group Wallpaper --group org.kde.image --group General \
--key Image "$LOCK_BG"
echo " [ok] lock screen wallpaper: NexusOS brushed metal"
fi
fi
# ── 9. GTK apps under Plasma ─────────────────────────────────────────────
if command -v kwriteconfig5 &>/dev/null; then
kwriteconfig5 --file kdeglobals --group KDE --key widgetStyle "kvantum-dark"
kwriteconfig5 --file kdeglobals --group Icons --key Theme NexusOS
kwriteconfig5 --file kdeglobals --group General \
--key font "Ubuntu,10,-1,5,50,0,0,0,0,0"
echo " [ok] kdeglobals: Kvantum style, NexusOS icons, Ubuntu 10"
fi
if command -v gsettings &>/dev/null; then
gsettings set org.gnome.desktop.interface gtk-theme NexusOS 2>/dev/null || true
gsettings set org.gnome.desktop.interface icon-theme NexusOS 2>/dev/null || true
echo " [ok] gsettings: GTK theme + icons = NexusOS"
fi
# ── 10. SDDM login theme ─────────────────────────────────────────────────
if [[ $NO_SDDM -eq 0 ]]; then
echo " Deploying SDDM theme + KDE session entry (requires sudo)..."
sudo cp -r "$KDE/sddm/NexusOS-QML" /usr/share/sddm/themes/
sudo cp "$REPO/management/sessions/nexusos-kde.desktop" /usr/share/xsessions/
if command -v kwriteconfig5 &>/dev/null; then
sudo kwriteconfig5 --file /etc/sddm.conf.d/nexusos.conf --group Theme --key Current NexusOS-QML
else
# Fallback: write the INI directly
sudo bash -c 'printf "[Theme]\nCurrent=NexusOS-QML\n" > /etc/sddm.conf.d/nexusos.conf'
fi
echo " [ok] SDDM theme: NexusOS-QML"
echo " [ok] KDE session: NexusOS-KDE added to /usr/share/xsessions/"
else
echo " [skip] SDDM (--no-sddm passed)"
fi
# ── 11. Promethean Terminal desktop launcher ──────────────────────────────
DESKTOP_SRC="$REPO/bin/promethean/promethean-terminal.desktop"
DESKTOP_DEST="$HOME/.local/share/applications/promethean-terminal.desktop"
if [[ -f "$DESKTOP_SRC" ]]; then
cp -f "$DESKTOP_SRC" "$DESKTOP_DEST"
echo " [ok] Promethean Terminal launcher updated"
fi
# ── 11b. Global Theme + wallpaper ────────────────────────────────────────
# Copied, NOT symlinked, unlike the theme dirs above: KPackage silently skips a
# symlinked package directory, so a symlinked look-and-feel never appears in
# `lookandfeeltool -l` or System Settings at all. Aurorae/desktoptheme/Kvantum
# read their directories directly and are fine as symlinks.
LNF_SRC="$KDE/look-and-feel/com.nexusos.desktop"
WALL_SRC="$KDE/wallpaper/NexusOS"
if [[ -d "$LNF_SRC" ]]; then
mkdir -p ~/.local/share/plasma/look-and-feel ~/.local/share/wallpapers
rm -rf ~/.local/share/plasma/look-and-feel/com.nexusos.desktop
cp -rL "$LNF_SRC" ~/.local/share/plasma/look-and-feel/
rm -rf ~/.local/share/wallpapers/NexusOS
cp -rL "$WALL_SRC" ~/.local/share/wallpapers/
echo " [ok] Global Theme + wallpaper packages installed"
if command -v lookandfeeltool &>/dev/null; then
# Verify registration before applying. KPackage reports nothing when it
# rejects a package, so without this check a botched install is silent and
# you only find out by opening System Settings.
if lookandfeeltool -l 2>/dev/null | grep -qx "com.nexusos.desktop"; then
lookandfeeltool -a com.nexusos.desktop 2>/dev/null \
&& echo " [ok] Global Theme applied (splash, colors, decoration)"
else
echo " [WARN] com.nexusos.desktop did not register with KPackage."
echo " Most likely it was symlinked instead of copied -- KPackage"
echo " skips symlinked package directories silently."
fi
fi
if command -v plasma-apply-wallpaperimage &>/dev/null; then
plasma-apply-wallpaperimage ~/.local/share/wallpapers/NexusOS &>/dev/null \
&& echo " [ok] wallpaper applied"
fi
fi
# ── 11c. Panel layout + dock ─────────────────────────────────────────────
# The XFCE panel rebuilt with native Plasma widgets, plus Plank for the dock
# (its config and NexusOS theme already exist under assets/themes/restore-snapshot).
#
# Applied ONCE, guarded by a marker file. This rewrites the panel from scratch,
# so re-running it on every restore would wipe any widget you added since. Pass
# --panel to force it, e.g. after a fresh install or to undo panel experiments.
PANEL_MARKER="$HOME/.config/nexusos-panel-applied"
PANEL_JS="$KDE/panel-layout.js"
if [[ -f "$PANEL_JS" ]] && { [[ ! -f "$PANEL_MARKER" ]] || [[ $FORCE_PANEL -eq 1 ]]; }; then
if qdbus org.kde.plasmashell /PlasmaShell evaluateScript \
"$(sed "s|__NEXUS_ROOT__|$REPO|g" "$PANEL_JS")" &>/dev/null; then
touch "$PANEL_MARKER"
echo " [ok] panel layout applied (top, 36px, Nexus launcher)"
else
echo " [skip] panel layout — plasmashell not running"
fi
elif [[ -f "$PANEL_MARKER" ]]; then
echo " [ok] panel layout already applied (--panel to redo)"
fi
# Plank autostart. Plank is a GTK X11 app and runs fine under Plasma; this is
# the same dock, config and theme the XFCE session used.
if command -v plank &>/dev/null; then
mkdir -p ~/.config/autostart
# Symlink, matching bin/panel/install.sh. cp fails outright when the target is
# already a symlink back to this same file ("are the same file"), which made
# the step look like it had silently done nothing.
ln -sfn "$REPO/management/autostart/plank.desktop" ~/.config/autostart/plank.desktop \
&& echo " [ok] Plank autostart installed"
pgrep -x plank &>/dev/null || { setsid plank </dev/null &>/dev/null & disown; }
fi
# ── 11d. Custom shortcut: region screenshot to clipboard ─────────────────
# Meta+Shift+S -> `xfce4-screenshooter -rc`, the equivalent of the XFCE binding.
# Spectacle is not installed by kde-plasma-desktop, and xfce4-screenshooter
# works fine under Plasma, so this keeps the tool that is already here.
#
# Written as ONE atomic replace rather than a series of kwriteconfig5 calls,
# because khotkeys watches khotkeysrc and rewrites it from its own model on
# every change.
#
# The UUID below is FIXED, not generated. kglobalaccel records the key binding
# in kglobalshortcutsrc against the action's UUID, so a fresh UUID on each run
# cannot take a key that the previous run's UUID already holds: the entry gets
# registered with no shortcut at all, and every re-run leaves another dead
# registration behind. A stable UUID means a re-run re-claims its own binding.
if ! grep -q "^Key=Meta+Shift+S$" ~/.config/khotkeysrc 2>/dev/null; then
python3 - <<'PYEOF'
import pathlib, re
# Fixed so re-runs reclaim the same kglobalaccel registration.
SHORTCUT_UUID = "87a4ba1e-4f01-4a79-9cd1-b73c17d459ea"
p = pathlib.Path.home() / ".config" / "khotkeysrc"
s = p.read_text() if p.exists() else "[Data]\nDataCount=0\n"
# Drop any half-written entry from an earlier failed attempt.
for m in re.findall(r"\[Data_(\d+)\]\n(?:[^\[]*)", s):
blk = re.search(r"\[Data_%s\]\n((?:[^\[]*))" % m, s)
if blk and "Screenshot region to clipboard" in blk.group(1):
s = re.sub(r"\n\[Data_%s[^\]]*\]\n(?:[^\[]*)" % m, "\n", s)
count = int(re.search(r"\[Data\]\nDataCount=(\d+)", s).group(1))
n = count + 1
s = re.sub(r"(\[Data\]\nDataCount=)\d+", r"\g<1>%d" % n, s, count=1)
s = s.rstrip("\n") + """
[Data_%d]
Comment=Select a region and copy it straight to the clipboard
Enabled=true
Name=Screenshot region to clipboard
Type=SIMPLE_ACTION_DATA
[Data_%dActions]
ActionsCount=1
[Data_%dActions0]
CommandURL=xfce4-screenshooter -rc
Type=COMMAND_URL
[Data_%dConditions]
Comment=
ConditionsCount=0
[Data_%dTriggers]
Comment=Simple_action
TriggersCount=1
[Data_%dTriggers0]
Key=Meta+Shift+S
Type=SHORTCUT
Uuid={%s}
""" % (n, n, n, n, n, n, SHORTCUT_UUID)
tmp = p.with_suffix(".nexustmp")
tmp.write_text(s)
tmp.replace(p)
PYEOF
qdbus org.kde.kded5 /modules/khotkeys reread_configuration &>/dev/null \
&& echo " [ok] Meta+Shift+S -> region screenshot to clipboard"
else
echo " [ok] screenshot shortcut already bound"
fi
# ── 12. Apply live changes (if Plasma is running) ────────────────────────
if qdbus org.kde.KWin /KWin reconfigure 2>/dev/null; then
echo " [ok] KWin reconfigured"
# Restart plasmashell to pick up new shell theme.
# setsid + closed stdio is load-bearing, not tidiness: the restarted shell
# outlives this script, and if it inherits our stdout it holds the write end
# of the caller's pipe open forever. `ncp restore` captures output, so a
# plain `kstart5 plasmashell &` hangs the entire restore after the theme is
# already applied -- which looks like a failure and isn't one.
if command -v kquitapp5 &>/dev/null && command -v kstart5 &>/dev/null; then
kquitapp5 plasmashell 2>/dev/null
sleep 1
setsid kstart5 plasmashell </dev/null >/dev/null 2>&1 &
disown 2>/dev/null || true
echo " [ok] plasmashell restarted"
fi
fi
echo ""
echo "NexusOS KDE theme installed. On first KDE session:"
echo " 1. System Settings → Appearance → verify all components show NexusOS"
echo " 2. Panel: right-click → Edit Panel to adjust height/position"
echo " 3. Konsole: Settings → Edit Profile → select Promethean (for Promethean Terminal)"
echo " 4. Test lock screen: Meta+L"