From 646675856f7ff38736fae960b434c0c7bb31ae1f Mon Sep 17 00:00:00 2001 From: Mustafa Date: Sat, 18 Apr 2026 22:25:37 -0700 Subject: [PATCH 1/2] fix(theme-cycler): persist theme selection to settings.json --- extensions/theme-cycler.ts | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/extensions/theme-cycler.ts b/extensions/theme-cycler.ts index 3b16d4c..5ad176f 100644 --- a/extensions/theme-cycler.ts +++ b/extensions/theme-cycler.ts @@ -17,11 +17,26 @@ * Usage: pi -e extensions/theme-cycler.ts -e extensions/minimal.ts */ +import * as fs from "fs"; +import * as path from "path"; +import * as os from "os"; import type { ExtensionAPI, ExtensionContext } from "@mariozechner/pi-coding-agent"; import { truncateToWidth } from "@mariozechner/pi-tui"; -import { applyExtensionDefaults } from "./themeMap.ts"; +import { applyExtensionDefaults } from "./lib/themeMap.ts"; export default function (pi: ExtensionAPI) { + function persistTheme(themeName: string): void { + try { + const settingsPath = path.join(os.homedir(), ".pi", "agent", "settings.json"); + const raw = fs.existsSync(settingsPath) ? fs.readFileSync(settingsPath, "utf-8") : "{}"; + const settings = JSON.parse(raw); + settings.theme = themeName; + fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n", "utf-8"); + } catch { + // best-effort + } + } + let currentCtx: ExtensionContext | undefined; let swatchTimer: ReturnType | null = null; @@ -94,6 +109,7 @@ export default function (pi: ExtensionAPI) { index = (index + direction + themes.length) % themes.length; const theme = themes[index]; const result = ctx.ui.setTheme(theme.name); + persistTheme(theme.name); if (result.success) { updateStatus(ctx); @@ -135,6 +151,7 @@ export default function (pi: ExtensionAPI) { if (arg) { const result = ctx.ui.setTheme(arg); + persistTheme(arg); if (result.success) { updateStatus(ctx); showSwatch(ctx); @@ -156,6 +173,7 @@ export default function (pi: ExtensionAPI) { const selectedName = selected.split(/\s/)[0]; const result = ctx.ui.setTheme(selectedName); + persistTheme(selectedName); if (result.success) { updateStatus(ctx); showSwatch(ctx); From 5d75979898899e4b4696d0d1b2302f95c0f2a26d Mon Sep 17 00:00:00 2001 From: Mustafa Date: Sat, 18 Apr 2026 23:18:45 -0700 Subject: [PATCH 2/2] fix(theme-cycler): restore saved theme in applyExtensionTheme, not session_start The previous fix persisted theme changes correctly but they still reverted on reload because all extensions call applyExtensionDefaults on session_start, and the last one to fire would overwrite the restored theme. Fix at the source: applyExtensionTheme() in themeMap.ts now checks settings.json first and honours the saved preference over themeMap defaults. This makes ALL extensions respect the user's saved theme automatically, with no timing hacks or per-extension workarounds needed. --- extensions/themeMap.ts | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/extensions/themeMap.ts b/extensions/themeMap.ts index ce4e563..97f86ee 100644 --- a/extensions/themeMap.ts +++ b/extensions/themeMap.ts @@ -12,8 +12,10 @@ */ import type { ExtensionContext } from "@mariozechner/pi-coding-agent"; -import { basename } from "path"; +import { basename, join } from "path"; import { fileURLToPath } from "url"; +import { homedir } from "os"; +import * as fs from "fs"; // ── Theme assignments ────────────────────────────────────────────────────── // @@ -71,6 +73,18 @@ export function applyExtensionTheme(fileUrl: string, ctx: ExtensionContext): boo return true; // Pretend we succeeded, but don't overwrite the primary theme } + // Always honour the user's saved theme preference over themeMap defaults + try { + const settingsPath = join(homedir(), ".pi", "agent", "settings.json"); + if (fs.existsSync(settingsPath)) { + const settings = JSON.parse(fs.readFileSync(settingsPath, "utf-8")); + if (settings.theme) { + return ctx.ui.setTheme(settings.theme).success; + } + } + } catch {} + + // No saved preference — fall back to themeMap default let themeName = THEME_MAP[name]; if (!themeName) {