From 79138c0e700f01dab19e9c105f24cbce7c1fc8aa Mon Sep 17 00:00:00 2001 From: Ryan Hughes Date: Fri, 28 Aug 2026 12:33:02 -0400 Subject: [PATCH 1/3] Follow the active theme in T3 Code T3 Code reads themes an environment publishes into its state directory, so a generated t3code.json carries the palette the same way claude.json and vscode-theme.json already do, and omarchy-theme-set-t3code republishes it on every theme change for the app to pick up live. The template overrides only the roles a theme actually designs -- terminal and code surfaces, text on canvas, borders, selection -- and leaves muted text, placeholders, and status foregrounds to T3 Code, which contrast-solves them against whatever canvas it is given. Overriding those directly cost readability on light themes: White fell to 1.0:1 on placeholder text. Installing from the menu now routes through omarchy-install-ai-t3-code so a fresh install publishes the current palette and opens wearing it. --- bin/omarchy-install-ai-t3-code | 49 ++++++++++++++++++++++++++++++ bin/omarchy-theme-set | 1 + bin/omarchy-theme-set-t3code | 34 +++++++++++++++++++++ default/omarchy/omarchy-menu.jsonc | 2 +- default/themed/t3code.json.tpl | 36 ++++++++++++++++++++++ test/shell.d/theme-staging-test.sh | 2 +- 6 files changed, 122 insertions(+), 2 deletions(-) create mode 100755 bin/omarchy-install-ai-t3-code create mode 100755 bin/omarchy-theme-set-t3code create mode 100644 default/themed/t3code.json.tpl diff --git a/bin/omarchy-install-ai-t3-code b/bin/omarchy-install-ai-t3-code new file mode 100755 index 00000000..1302b7ee --- /dev/null +++ b/bin/omarchy-install-ai-t3-code @@ -0,0 +1,49 @@ +#!/bin/bash + +# omarchy:summary=Install T3 Code and point it at the Omarchy palette +# omarchy:requires-sudo=true + +set -e + +T3CODE_HOME="${T3CODE_HOME:-$HOME/.t3}" +T3CODE_STATE_DIR="$T3CODE_HOME/userdata" +T3CODE_SETTINGS_PATH="$T3CODE_STATE_DIR/settings.json" + +# Ask T3 Code to open on the palette this machine publishes. `t3 theme set` +# is the supported way, but the desktop package ships only the GUI -- the CLI +# is a separate npm distribution -- so fall back to the setting it writes. +# Both run before the first launch, so neither races a running server. +set_default_theme() { + if command -v t3 >/dev/null 2>&1; then + t3 theme set omarchy --base-dir "$T3CODE_HOME" >/dev/null && return + fi + + local tmp + mkdir -p "$T3CODE_STATE_DIR" + [[ -f $T3CODE_SETTINGS_PATH ]] || echo '{}' >"$T3CODE_SETTINGS_PATH" + + tmp=$(mktemp "$T3CODE_SETTINGS_PATH.XXXXXX") + if jq '.defaultTheme = "omarchy"' "$T3CODE_SETTINGS_PATH" >"$tmp"; then + mv "$tmp" "$T3CODE_SETTINGS_PATH" + else + rm -f "$tmp" + echo "Could not set the default theme in $T3CODE_SETTINGS_PATH." >&2 + fi +} + +echo "Installing T3 Code..." +omarchy-pkg-add t3code-bin + +# The palette itself, and the request to open on it, are both first-run +# concerns. `defaultTheme` only decides what a client with no theme of its own +# starts on, so choosing a theme in T3 Code later is never overridden. +echo "Matching T3 Code to the current theme..." +mkdir -p "$T3CODE_STATE_DIR" +omarchy-theme-set-t3code +set_default_theme + +echo "Opening T3 Code..." +setsid uwsm-app -- gtk-launch t3code >/dev/null 2>&1 & + +echo "" +echo "T3 Code has been installed." diff --git a/bin/omarchy-theme-set b/bin/omarchy-theme-set index 614a8a1b..782b4ba7 100755 --- a/bin/omarchy-theme-set +++ b/bin/omarchy-theme-set @@ -372,6 +372,7 @@ post_theme_commands=( omarchy-theme-set-pi omarchy-theme-set-claude omarchy-theme-set-hermes + omarchy-theme-set-t3code omarchy-theme-set-browser omarchy-theme-set-vscode omarchy-theme-set-obsidian diff --git a/bin/omarchy-theme-set-t3code b/bin/omarchy-theme-set-t3code new file mode 100755 index 00000000..7b6f69bf --- /dev/null +++ b/bin/omarchy-theme-set-t3code @@ -0,0 +1,34 @@ +#!/bin/bash + +# omarchy:summary=Sync the generated Omarchy theme to T3 Code +# omarchy:hidden=true + +set -euo pipefail + +T3CODE_SOURCE_PATH="$HOME/.local/state/omarchy/current/theme/t3code.json" +T3CODE_HOME="${T3CODE_HOME:-$HOME/.t3}" +T3CODE_STATE_DIR="$T3CODE_HOME/userdata" +# The filename is the theme id T3 Code shows and `t3 theme set` accepts, and +# it stays stable while the colors change underneath on every theme switch. +T3CODE_THEME_PATH="$T3CODE_STATE_DIR/themes/omarchy.json" + +[[ -f $T3CODE_SOURCE_PATH ]] || exit 0 + +# A theme without an accent or a background leaves its placeholder unresolved. +# Publishing that would only make T3 Code reject the file, so skip instead and +# leave the previous palette in place. +if grep -q '{{' "$T3CODE_SOURCE_PATH"; then + echo "Skipping T3 Code theme: $(basename "$T3CODE_SOURCE_PATH") has unresolved colors." >&2 + exit 0 +fi + +# Only follow an install that already exists. Creating the directory here would +# leave a stray T3 Code state dir on machines that do not run it. +[[ -d $T3CODE_STATE_DIR ]] || exit 0 + +# T3 Code watches this file and retints every connected client on change, so +# the write has to be atomic: a half-written file would read as invalid. +mkdir -p "$(dirname "$T3CODE_THEME_PATH")" +tmp=$(mktemp "$T3CODE_THEME_PATH.XXXXXX") +cp "$T3CODE_SOURCE_PATH" "$tmp" +mv "$tmp" "$T3CODE_THEME_PATH" diff --git a/default/omarchy/omarchy-menu.jsonc b/default/omarchy/omarchy-menu.jsonc index 0e590652..745ec311 100644 --- a/default/omarchy/omarchy-menu.jsonc +++ b/default/omarchy/omarchy-menu.jsonc @@ -248,7 +248,7 @@ "install.ai.ollama": {"icon":"","iconFont":"omarchy","label":"Ollama","disabled":"omarchy-cmd-present ollama","action":"if omarchy-cmd-present nvidia-smi; then ollama_pkg=ollama-cuda; elif omarchy-cmd-present rocminfo; then ollama_pkg=ollama-rocm; else ollama_pkg=ollama; fi; omarchy-install-app Ollama \"$ollama_pkg\""}, "install.ai.openclaw": {"icon":"","iconFont":"omarchy","label":"OpenClaw","disabled":"omarchy-pkg-present openclaw","action":"omarchy-launch-floating-terminal-with-presentation omarchy-install-ai-openclaw"}, "install.ai.perplexity": {"icon":"","iconFont":"omarchy","label":"Perplexity","disabled":"omarchy-pkg-present perplexity","action":"omarchy-install-and-launch Perplexity perplexity perplexity"}, - "install.ai.t3-code": {"icon":"","iconFont":"omarchy","label":"T3 Code","disabled":"omarchy-pkg-present t3code-bin","action":"omarchy-install-and-launch 'T3 Code' t3code-bin t3code"}, + "install.ai.t3-code": {"icon":"","iconFont":"omarchy","label":"T3 Code","disabled":"omarchy-pkg-present t3code-bin","action":"omarchy-launch-floating-terminal-with-presentation omarchy-install-ai-t3-code"}, "install.gaming.steam": {"icon":"","label":"Steam","disabled":"omarchy-pkg-present steam","action":"omarchy-launch-floating-terminal-with-presentation omarchy-install-gaming-steam"}, "install.gaming.retroarch": {"icon":"󰯉","label":"RetroArch","disabled":"omarchy-pkg-present retroarch","action":"omarchy-launch-floating-terminal-with-presentation omarchy-install-gaming-retroarch"}, "install.gaming.minecraft": {"icon":"󰍳","label":"Minecraft","disabled":"omarchy-pkg-present minecraft-launcher","action":"omarchy-install-and-launch Minecraft minecraft-launcher minecraft-launcher"}, diff --git a/default/themed/t3code.json.tpl b/default/themed/t3code.json.tpl new file mode 100644 index 00000000..e420dcc4 --- /dev/null +++ b/default/themed/t3code.json.tpl @@ -0,0 +1,36 @@ +{ + "name": "Omarchy", + "appearance": "{{ mode }}", + "canvas": "{{ background }}", + "accent": "{{ accent }}", + "colors": { + "chrome": "{{ background }}", + "toolbar": "{{ background }}", + "toolbarForeground": "{{ foreground }}", + "toolbarBorder": "{{ muted }}", + + "text": "{{ foreground }}", + "border": "{{ muted }}", + "focus": "{{ accent }}", + + "sidebar": "{{ dark_background }}", + "sidebarForeground": "{{ foreground }}", + "sidebarBorder": "{{ muted }}", + "sidebarRowHover": "{{ mix dark_background foreground 6% }}", + "sidebarRowActive": "{{ mix dark_background accent 18% }}", + "sidebarRowSelected": "{{ selection }}", + + "error": "{{ mix red foreground 35% }}", + "warning": "{{ mix yellow foreground 35% }}", + + "codeBackground": "{{ dark_background }}", + "codeForeground": "{{ foreground }}", + + "terminalBackground": "{{ background }}", + "terminalForeground": "{{ foreground }}", + "terminalCursor": "{{ bright_foreground }}", + "terminalSelection": "{{ selection }}", + "terminalScrollbar": "{{ muted }}", + "terminalScrollbarHover": "{{ dark_foreground }}" + } +} diff --git a/test/shell.d/theme-staging-test.sh b/test/shell.d/theme-staging-test.sh index 9ec3b0f9..1fc7a4a5 100755 --- a/test/shell.d/theme-staging-test.sh +++ b/test/shell.d/theme-staging-test.sh @@ -207,7 +207,7 @@ pass "a theme name cannot climb out of the theme directories" # generates. Every generated theme file is either denied to an installed theme or # recorded here as carrying colour, so a new template fails until it is placed. denied=(alacritty.toml foot.ini ghostty.conf kitty.conf gum_env.lua hyprland.lua neovim.lua vscode.json) -colour_only=(btop.theme chromium.theme claude.json helix.toml hermes.yaml hyprland-preview-share-picker.css keyboard.rgb obsidian.css pi.json shell.toml vscode-theme.json) +colour_only=(btop.theme chromium.theme claude.json helix.toml hermes.yaml hyprland-preview-share-picker.css keyboard.rgb obsidian.css pi.json shell.toml t3code.json vscode-theme.json) for tpl in "$ROOT"/default/themed/*.tpl; do generated=$(basename "$tpl" .tpl) From 72ec724c3c24feaf419d30931d74b50bb8d6865b Mon Sep 17 00:00:00 2001 From: Ryan Hughes Date: Fri, 28 Aug 2026 13:06:18 -0400 Subject: [PATCH 2/3] Use omarchy-cmd-present --- bin/omarchy-install-ai-t3-code | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/omarchy-install-ai-t3-code b/bin/omarchy-install-ai-t3-code index 1302b7ee..e93e9b15 100755 --- a/bin/omarchy-install-ai-t3-code +++ b/bin/omarchy-install-ai-t3-code @@ -14,7 +14,7 @@ T3CODE_SETTINGS_PATH="$T3CODE_STATE_DIR/settings.json" # is a separate npm distribution -- so fall back to the setting it writes. # Both run before the first launch, so neither races a running server. set_default_theme() { - if command -v t3 >/dev/null 2>&1; then + if omarchy-cmd-present t3; then t3 theme set omarchy --base-dir "$T3CODE_HOME" >/dev/null && return fi From 2ea76f8fe23d9e74c63396d3a33b923fe2beb0e5 Mon Sep 17 00:00:00 2001 From: Ryan Hughes Date: Mon, 7 Sep 2026 12:57:08 -0400 Subject: [PATCH 3/3] Refresh the current palette before installing T3 Code --- bin/omarchy-install-ai-t3-code | 36 ++++--------- test/shell.d/t3code-install-test.sh | 81 +++++++++++++++++++++++++++++ 2 files changed, 90 insertions(+), 27 deletions(-) create mode 100755 test/shell.d/t3code-install-test.sh diff --git a/bin/omarchy-install-ai-t3-code b/bin/omarchy-install-ai-t3-code index e93e9b15..b9e3af38 100755 --- a/bin/omarchy-install-ai-t3-code +++ b/bin/omarchy-install-ai-t3-code @@ -7,40 +7,22 @@ set -e T3CODE_HOME="${T3CODE_HOME:-$HOME/.t3}" T3CODE_STATE_DIR="$T3CODE_HOME/userdata" -T3CODE_SETTINGS_PATH="$T3CODE_STATE_DIR/settings.json" - -# Ask T3 Code to open on the palette this machine publishes. `t3 theme set` -# is the supported way, but the desktop package ships only the GUI -- the CLI -# is a separate npm distribution -- so fall back to the setting it writes. -# Both run before the first launch, so neither races a running server. -set_default_theme() { - if omarchy-cmd-present t3; then - t3 theme set omarchy --base-dir "$T3CODE_HOME" >/dev/null && return - fi - - local tmp - mkdir -p "$T3CODE_STATE_DIR" - [[ -f $T3CODE_SETTINGS_PATH ]] || echo '{}' >"$T3CODE_SETTINGS_PATH" - - tmp=$(mktemp "$T3CODE_SETTINGS_PATH.XXXXXX") - if jq '.defaultTheme = "omarchy"' "$T3CODE_SETTINGS_PATH" >"$tmp"; then - mv "$tmp" "$T3CODE_SETTINGS_PATH" - else - rm -f "$tmp" - echo "Could not set the default theme in $T3CODE_SETTINGS_PATH." >&2 - fi -} echo "Installing T3 Code..." omarchy-pkg-add t3code-bin -# The palette itself, and the request to open on it, are both first-run -# concerns. `defaultTheme` only decides what a client with no theme of its own -# starts on, so choosing a theme in T3 Code later is never overridden. echo "Matching T3 Code to the current theme..." mkdir -p "$T3CODE_STATE_DIR" + +# An updated user's current theme may have been staged before this template existed. +if [[ ! -f $HOME/.local/state/omarchy/current/theme/t3code.json ]]; then + omarchy-theme-refresh +fi + omarchy-theme-set-t3code -set_default_theme + +# The packaged CLI selects the published palette before the app's first launch. +t3 theme set omarchy --base-dir "$T3CODE_HOME" echo "Opening T3 Code..." setsid uwsm-app -- gtk-launch t3code >/dev/null 2>&1 & diff --git a/test/shell.d/t3code-install-test.sh b/test/shell.d/t3code-install-test.sh new file mode 100755 index 00000000..66bc9ecd --- /dev/null +++ b/test/shell.d/t3code-install-test.sh @@ -0,0 +1,81 @@ +#!/bin/bash + +set -euo pipefail + +source "$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)/base-test.sh" + +test_tmp=$(mktemp -d) +trap 'rm -rf "$test_tmp"' EXIT + +test_home="$test_tmp/home" +mock_bin="$test_tmp/bin" +mkdir -p "$mock_bin" + +# Run the real theme refresh, renderer and publisher in a throwaway home. +# Only package installation, the T3 CLI and desktop launch are stubbed. +cat >"$mock_bin/omarchy-pkg-add" <<'SH' +#!/bin/bash +[[ $1 == "t3code-bin" ]] +SH + +cat >"$mock_bin/t3" <<'SH' +#!/bin/bash +[[ $1 == "theme" && $2 == "set" && $3 == "omarchy" && $4 == "--base-dir" && $5 == "$T3CODE_HOME" ]] || exit 1 +palette="$T3CODE_HOME/userdata/themes/omarchy.json" +if [[ ! -f $palette ]] || ! jq -e '.name == "Omarchy" and (.accent | test("^#[0-9a-fA-F]{6}$"))' "$palette" >/dev/null; then + echo "No published Omarchy theme" + exit 1 +fi +if [[ ${OMARCHY_TEST_T3_FAIL:-0} == "1" ]]; then + echo "T3 theme selection failed" + exit 1 +fi +echo "T3 selected Omarchy" +SH + +cat >"$mock_bin/setsid" <<'SH' +#!/bin/bash +exit 0 +SH +chmod +x "$mock_bin"/* + +run_installer() { + HOME="$test_home" T3CODE_HOME="$test_tmp/custom t3 home" \ + OMARCHY_PATH="$ROOT" PATH="$mock_bin:$ROOT/bin:$PATH" \ + OMARCHY_THEME_HEADLESS=1 XDG_RUNTIME_DIR="$test_tmp" \ + "$ROOT/bin/omarchy-install-ai-t3-code" >"$test_tmp/output" 2>&1 +} + +state="$test_home/.local/state/omarchy/current" +palette="$test_tmp/custom t3 home/userdata/themes/omarchy.json" +settings="$test_tmp/custom t3 home/userdata/settings.json" +mkdir -p "$state/theme" +echo 'tokyo-night' >"$state/theme.name" +cp "$ROOT/themes/tokyo-night/colors.toml" "$state/theme/colors.toml" + +run_installer || fail "installing after an update succeeds" "$(cat "$test_tmp/output")" +[[ -f $state/theme/t3code.json && -f $palette ]] || fail "the missing palette is rendered and published" +cmp -s "$state/theme/t3code.json" "$palette" || fail "T3 receives the current theme's palette" +grep -q 'T3 selected Omarchy' "$test_tmp/output" || fail "the published palette is selected" +grep -q 'Opening T3 Code' "$test_tmp/output" || fail "the themed app opens" +[[ ! -e $test_home/.t3 ]] || fail "the custom T3 home is respected" +pass "an update with no staged T3 palette renders, publishes and selects it before launch" + +# Preserve an already rendered palette, including a user-supplied color. +jq '.accent = "#abcdef"' "$state/theme/t3code.json" >"$test_tmp/palette.json" +cp "$test_tmp/palette.json" "$state/theme/t3code.json" +run_installer || fail "installing with an existing palette succeeds" "$(cat "$test_tmp/output")" +cmp -s "$test_tmp/palette.json" "$palette" || fail "an existing palette is published without re-staging" +pass "an existing palette is used without refreshing the current theme" + +printf '{"defaultTheme":"dark","keep":"existing settings"}\n' >"$settings" +cp "$settings" "$test_tmp/settings-before.json" +if OMARCHY_TEST_T3_FAIL=1 run_installer; then + fail "a failed T3 theme selection fails the installer" +fi +grep -q 'T3 theme selection failed' "$test_tmp/output" || fail "the CLI failure is visible" +if grep -Eq 'Opening T3 Code|T3 Code has been installed' "$test_tmp/output"; then + fail "a failed selection does not report successful setup" +fi +cmp -s "$test_tmp/settings-before.json" "$settings" || fail "a failed selection does not rewrite settings" +pass "a CLI failure remains visible and leaves the existing settings intact"