From da53c0ff60e9d41a00a84c6afd35c3d132225b4a Mon Sep 17 00:00:00 2001 From: Ryan Hughes Date: Wed, 20 May 2026 01:53:34 -0400 Subject: [PATCH] Add Pi theme based on system theme Based entirely on the work of @robzolkos in #5711. That attempt was adapted to better fit the standard templating system while also adding color mixing for use in other themes. --- bin/omarchy-theme-set | 1 + bin/omarchy-theme-set-pi | 76 +++++++++++++++ .../agent/extensions/omarchy-system-theme.ts | 41 -------- default/themed/pi.json.tpl | 95 +++++++++++++++++++ install/config/pi.sh | 3 +- migrations/1778151386.sh | 4 - migrations/1779242346.sh | 5 + test/omarchy-cli-test.sh | 74 +++++++++++++++ 8 files changed, 252 insertions(+), 47 deletions(-) create mode 100755 bin/omarchy-theme-set-pi delete mode 100644 default/pi/agent/extensions/omarchy-system-theme.ts create mode 100644 default/themed/pi.json.tpl delete mode 100644 migrations/1778151386.sh create mode 100644 migrations/1779242346.sh diff --git a/bin/omarchy-theme-set b/bin/omarchy-theme-set index 5a682a2e..1f0c58ad 100755 --- a/bin/omarchy-theme-set +++ b/bin/omarchy-theme-set @@ -173,6 +173,7 @@ post_theme_commands=( omarchy-restart-helix omarchy-theme-set-foot omarchy-theme-set-gnome + omarchy-theme-set-pi omarchy-theme-set-browser omarchy-theme-set-vscode omarchy-theme-set-obsidian diff --git a/bin/omarchy-theme-set-pi b/bin/omarchy-theme-set-pi new file mode 100755 index 00000000..f75e75fd --- /dev/null +++ b/bin/omarchy-theme-set-pi @@ -0,0 +1,76 @@ +#!/bin/bash + +# omarchy:summary=Sync the generated Omarchy Pi theme +# omarchy:args=[--activate] +# omarchy:hidden=true + +set -euo pipefail + +CURRENT_THEME_PATH="$HOME/.config/omarchy/current/theme" +PI_SOURCE_PATH="$CURRENT_THEME_PATH/pi.json" +PI_AGENT_DIR="$HOME/.pi/agent" +PI_THEME_DIR="$PI_AGENT_DIR/themes" +PI_THEME_PATH="$PI_THEME_DIR/omarchy-system.json" +PI_SETTINGS_PATH="$PI_AGENT_DIR/settings.json" +PI_ACTIVATE=0 + +usage() { + echo "Usage: omarchy-theme-set-pi [--activate]" +} + +for arg in "$@"; do + case "$arg" in + --activate) + PI_ACTIVATE=1 + ;; + -h | --help) + usage + exit 0 + ;; + *) + usage >&2 + exit 1 + ;; + esac +done + +if [[ ! -f $PI_SOURCE_PATH ]]; then + if (( PI_ACTIVATE == 1 )); then + echo "Pi theme source missing: $PI_SOURCE_PATH" >&2 + echo "Run omarchy-theme-refresh after selecting an Omarchy theme." >&2 + exit 1 + fi + + exit 0 +fi + +if (( PI_ACTIVATE == 0 )) && [[ ! -d $PI_AGENT_DIR ]]; then + exit 0 +fi + +write_setting_theme() { + local tmp + + mkdir -p "$PI_AGENT_DIR" + + if [[ -f $PI_SETTINGS_PATH ]]; then + tmp=$(mktemp "$PI_SETTINGS_PATH.XXXXXX") + jq '.theme = "omarchy-system"' "$PI_SETTINGS_PATH" >"$tmp" + mv "$tmp" "$PI_SETTINGS_PATH" + else + cat >"$PI_SETTINGS_PATH" < | null = null; - - pi.on("session_start", (_event, ctx) => { - let currentTheme = omarchyPiTheme(); - ctx.ui.setTheme(currentTheme); - - intervalId = setInterval(() => { - const nextTheme = omarchyPiTheme(); - if (nextTheme !== currentTheme) { - currentTheme = nextTheme; - ctx.ui.setTheme(currentTheme); - } - }, 2000); - }); - - pi.on("session_shutdown", () => { - if (intervalId) { - clearInterval(intervalId); - intervalId = null; - } - }); -} diff --git a/default/themed/pi.json.tpl b/default/themed/pi.json.tpl new file mode 100644 index 00000000..6b1a969d --- /dev/null +++ b/default/themed/pi.json.tpl @@ -0,0 +1,95 @@ +{ + "$schema": "https://raw.githubusercontent.com/earendil-works/pi/main/packages/coding-agent/src/modes/interactive/theme/theme-schema.json", + "name": "omarchy-system", + "vars": { + "background": "{{ background }}", + "foreground": "{{ foreground }}", + "accent": "{{ accent }}", + "selectionBackground": "{{ selection_background }}", + "selectionForeground": "{{ selection_foreground }}", + "selectedBackground": "{{ mix background accent 22% }}", + "color0": "{{ color0 }}", + "color1": "{{ color1 }}", + "color2": "{{ color2 }}", + "color3": "{{ color3 }}", + "color4": "{{ color4 }}", + "color5": "{{ color5 }}", + "color6": "{{ color6 }}", + "color7": "{{ color7 }}", + "color8": "{{ color8 }}", + "color9": "{{ color9 }}", + "color10": "{{ color10 }}", + "color11": "{{ color11 }}", + "color12": "{{ color12 }}", + "color13": "{{ color13 }}", + "color14": "{{ color14 }}", + "color15": "{{ color15 }}", + "panel": "{{ mix background foreground 6% }}", + "panelAlt": "{{ mix background foreground 10% }}", + "panelPending": "{{ mix background accent 12% }}", + "panelSuccess": "{{ mix background color2 12% }}", + "panelError": "{{ mix background color1 12% }}", + "border": "{{ mix background foreground 30% }}", + "borderMuted": "{{ mix background foreground 20% }}", + "mutedText": "{{ mix foreground background 34% }}", + "dimText": "{{ mix foreground background 52% }}" + }, + "colors": { + "accent": "accent", + "border": "border", + "borderAccent": "accent", + "borderMuted": "borderMuted", + "success": "color2", + "error": "color1", + "warning": "color3", + "muted": "mutedText", + "dim": "dimText", + "text": "foreground", + "thinkingText": "dimText", + "selectedBg": "selectedBackground", + "userMessageBg": "panel", + "userMessageText": "foreground", + "customMessageBg": "panel", + "customMessageText": "foreground", + "customMessageLabel": "accent", + "toolPendingBg": "panelPending", + "toolSuccessBg": "panelSuccess", + "toolErrorBg": "panelError", + "toolTitle": "accent", + "toolOutput": "foreground", + "mdHeading": "color5", + "mdLink": "accent", + "mdLinkUrl": "color6", + "mdCode": "color6", + "mdCodeBlock": "foreground", + "mdCodeBlockBorder": "borderMuted", + "mdQuote": "mutedText", + "mdQuoteBorder": "borderMuted", + "mdHr": "borderMuted", + "mdListBullet": "color5", + "toolDiffAdded": "color2", + "toolDiffRemoved": "color1", + "toolDiffContext": "mutedText", + "syntaxComment": "dimText", + "syntaxKeyword": "color5", + "syntaxFunction": "color4", + "syntaxVariable": "accent", + "syntaxString": "color2", + "syntaxNumber": "color3", + "syntaxType": "color4", + "syntaxOperator": "color5", + "syntaxPunctuation": "mutedText", + "thinkingOff": "borderMuted", + "thinkingMinimal": "accent", + "thinkingLow": "color4", + "thinkingMedium": "color5", + "thinkingHigh": "color3", + "thinkingXhigh": "color1", + "bashMode": "color3" + }, + "export": { + "pageBg": "{{ background }}", + "cardBg": "{{ mix background foreground 6% }}", + "infoBg": "{{ mix background foreground 10% }}" + } +} diff --git a/install/config/pi.sh b/install/config/pi.sh index 4afefecb..a8a6ae07 100644 --- a/install/config/pi.sh +++ b/install/config/pi.sh @@ -1,2 +1 @@ -mkdir -p ~/.pi/agent/extensions -cp "$OMARCHY_PATH/default/pi/agent/extensions/omarchy-system-theme.ts" ~/.pi/agent/extensions/ +omarchy-theme-set-pi --activate diff --git a/migrations/1778151386.sh b/migrations/1778151386.sh deleted file mode 100644 index 5f9fb388..00000000 --- a/migrations/1778151386.sh +++ /dev/null @@ -1,4 +0,0 @@ -echo "Add Omarchy pi system theme extension" - -mkdir -p "$HOME/.pi/agent/extensions" -cp "$OMARCHY_PATH/default/pi/agent/extensions/omarchy-system-theme.ts" "$HOME/.pi/agent/extensions/" diff --git a/migrations/1779242346.sh b/migrations/1779242346.sh new file mode 100644 index 00000000..c07ba7d2 --- /dev/null +++ b/migrations/1779242346.sh @@ -0,0 +1,5 @@ +echo "Replace Pi's Omarchy light/dark extension with the generated omarchy-system theme" + +rm -f "$HOME/.pi/agent/extensions/omarchy-system-theme.ts" +omarchy-theme-refresh +omarchy-theme-set-pi --activate diff --git a/test/omarchy-cli-test.sh b/test/omarchy-cli-test.sh index 51f7226f..82b3851b 100644 --- a/test/omarchy-cli-test.sh +++ b/test/omarchy-cli-test.sh @@ -5,6 +5,7 @@ set -euo pipefail ROOT=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd) CLI="$ROOT/bin/omarchy" TMPDIR="" +PI_TMPDIR="" export PATH="$ROOT/bin:$PATH" @@ -33,6 +34,7 @@ assert_output_contains() { cleanup() { [[ -n $TMPDIR && -d $TMPDIR ]] && rm -rf "$TMPDIR" + [[ -n $PI_TMPDIR && -d $PI_TMPDIR ]] && rm -rf "$PI_TMPDIR" } trap cleanup EXIT @@ -188,6 +190,78 @@ pass "safe dispatch works for font list" "$CLI" font current >/dev/null pass "safe dispatch works for font current" +PI_TMPDIR=$(mktemp -d) +NEXT_THEME="$PI_TMPDIR/.config/omarchy/current/next-theme" +CURRENT_THEME="$PI_TMPDIR/.config/omarchy/current/theme" +USER_THEMED="$PI_TMPDIR/.config/omarchy/themed" +mkdir -p "$NEXT_THEME" "$CURRENT_THEME" "$USER_THEMED" + +cat >"$NEXT_THEME/colors.toml" <<'EOF' +accent = "#336699" +cursor = "#ffffff" +foreground = "#ffffff" +background = "#000000" +selection_foreground = "#000000" +selection_background = "#808080" +color0 = "#000000" +color1 = "#ff0000" +color2 = "#00ff00" +color3 = "#ffff00" +color4 = "#0000ff" +color5 = "#ff00ff" +color6 = "#00ffff" +color7 = "#ffffff" +color8 = "#111111" +color9 = "#ff1111" +color10 = "#11ff11" +color11 = "#ffff11" +color12 = "#1111ff" +color13 = "#ff11ff" +color14 = "#11ffff" +color15 = "#eeeeee" +EOF + +cat >"$USER_THEMED/mix-test.txt.tpl" <<'EOF' +mix={{ mix background foreground 50% }} +strip={{ mix_strip background foreground 50% }} +rgb={{ mix_rgb background foreground 50% }} +EOF + +OMARCHY_PATH="$ROOT" HOME="$PI_TMPDIR" "$ROOT/bin/omarchy-theme-set-templates" +grep -qx 'mix=#808080' "$NEXT_THEME/mix-test.txt" || fail "theme template mix helper works" +grep -qx 'strip=808080' "$NEXT_THEME/mix-test.txt" || fail "theme template mix_strip helper works" +grep -qx 'rgb=128,128,128' "$NEXT_THEME/mix-test.txt" || fail "theme template mix_rgb helper works" +pass "theme template color mix helpers work" + +jq -e '.name == "omarchy-system" and .vars.panel == "#0f0f0f" and .vars.border == "#4d4d4d" and .colors.accent == "accent"' "$NEXT_THEME/pi.json" >/dev/null +pass "pi theme template is generated from standard themed templates" +cp "$NEXT_THEME/pi.json" "$CURRENT_THEME/pi.json" + +echo '{"name":"omarchy-system","vars":{"custom":"yes"}}' >"$NEXT_THEME/pi.json" +OMARCHY_PATH="$ROOT" HOME="$PI_TMPDIR" "$ROOT/bin/omarchy-theme-set-templates" +jq -e '.name == "omarchy-system" and .vars.custom == "yes"' "$NEXT_THEME/pi.json" >/dev/null +pass "theme-specific pi.json overrides the default template" + +HOME="$PI_TMPDIR" "$ROOT/bin/omarchy-theme-set-pi" +[[ ! -d $PI_TMPDIR/.pi ]] || fail "pi theme sync skips missing Pi agent when not activating" +pass "pi theme sync skips missing Pi agent when not activating" + +HOME="$PI_TMPDIR" "$ROOT/bin/omarchy-theme-set-pi" --activate +[[ -f $PI_TMPDIR/.pi/agent/themes/omarchy-system.json ]] || fail "pi theme file is synced" +pass "pi theme file is synced" +[[ -f $PI_TMPDIR/.pi/agent/settings.json ]] || fail "pi settings file is generated" +pass "pi settings file is generated" +jq -e '.name == "omarchy-system" and .vars.panel == "#0f0f0f"' "$PI_TMPDIR/.pi/agent/themes/omarchy-system.json" >/dev/null +pass "pi synced theme JSON is valid" +jq -e '.theme == "omarchy-system"' "$PI_TMPDIR/.pi/agent/settings.json" >/dev/null +pass "pi generated theme is activated" + +jq '.model = "keep-me"' "$PI_TMPDIR/.pi/agent/settings.json" >"$PI_TMPDIR/settings.json.tmp" +mv "$PI_TMPDIR/settings.json.tmp" "$PI_TMPDIR/.pi/agent/settings.json" +HOME="$PI_TMPDIR" "$ROOT/bin/omarchy-theme-set-pi" --activate +jq -e '.theme == "omarchy-system" and .model == "keep-me"' "$PI_TMPDIR/.pi/agent/settings.json" >/dev/null +pass "pi theme activation preserves existing settings" + for binary in \ omarchy-update \ omarchy-theme-set \