From c447e62662ebba257f3ca13d5c1bc99aeb0a680d Mon Sep 17 00:00:00 2001 From: Mario Zechner Date: Sun, 4 Jan 2026 18:39:00 +0100 Subject: [PATCH] fix(theme): add optional themeOverride param to getSettingsListTheme/getSelectListTheme When hooks are loaded via jiti, they get a separate module instance from the main app. This means the global 'theme' variable in the hook's module is never initialized. Adding an optional theme parameter allows hooks to pass the theme from ctx.ui.custom() callback. Usage in hooks: getSettingsListTheme(theme) // theme from ctx.ui.custom callback --- packages/coding-agent/examples/hooks/tools.ts | 15 +++-------- .../src/modes/interactive/theme/theme.ts | 26 ++++++++++--------- 2 files changed, 17 insertions(+), 24 deletions(-) diff --git a/packages/coding-agent/examples/hooks/tools.ts b/packages/coding-agent/examples/hooks/tools.ts index cdb8d149..7cd02862 100644 --- a/packages/coding-agent/examples/hooks/tools.ts +++ b/packages/coding-agent/examples/hooks/tools.ts @@ -9,8 +9,9 @@ * 2. Use /tools to open the tool selector */ +import { getSettingsListTheme } from "@mariozechner/pi-coding-agent"; import type { HookAPI, HookContext } from "@mariozechner/pi-coding-agent/hooks"; -import { Container, type SettingItem, SettingsList, type SettingsListTheme } from "@mariozechner/pi-tui"; +import { Container, type SettingItem, SettingsList } from "@mariozechner/pi-tui"; // State persisted to session interface ToolsState { @@ -87,20 +88,10 @@ export default function toolsHook(pi: HookAPI) { })(), ); - // Create theme for SettingsList using the passed theme - const settingsTheme: SettingsListTheme = { - label: (text: string, selected: boolean) => (selected ? theme.fg("accent", text) : text), - value: (text: string, selected: boolean) => - selected ? theme.fg("accent", text) : theme.fg("muted", text), - description: (text: string) => theme.fg("dim", text), - cursor: theme.fg("accent", "→ "), - hint: (text: string) => theme.fg("dim", text), - }; - const settingsList = new SettingsList( items, Math.min(items.length + 2, 15), - settingsTheme, + getSettingsListTheme(theme), (id, newValue) => { // Update enabled state and apply immediately if (newValue === "enabled") { diff --git a/packages/coding-agent/src/modes/interactive/theme/theme.ts b/packages/coding-agent/src/modes/interactive/theme/theme.ts index 69b3db7a..461b507c 100644 --- a/packages/coding-agent/src/modes/interactive/theme/theme.ts +++ b/packages/coding-agent/src/modes/interactive/theme/theme.ts @@ -946,13 +946,14 @@ export function getMarkdownTheme(): MarkdownTheme { }; } -export function getSelectListTheme(): SelectListTheme { +export function getSelectListTheme(themeOverride?: Theme): SelectListTheme { + const t = themeOverride ?? theme; return { - selectedPrefix: (text: string) => theme.fg("accent", text), - selectedText: (text: string) => theme.fg("accent", text), - description: (text: string) => theme.fg("muted", text), - scrollInfo: (text: string) => theme.fg("muted", text), - noMatch: (text: string) => theme.fg("muted", text), + selectedPrefix: (text: string) => t.fg("accent", text), + selectedText: (text: string) => t.fg("accent", text), + description: (text: string) => t.fg("muted", text), + scrollInfo: (text: string) => t.fg("muted", text), + noMatch: (text: string) => t.fg("muted", text), }; } @@ -963,12 +964,13 @@ export function getEditorTheme(): EditorTheme { }; } -export function getSettingsListTheme(): import("@mariozechner/pi-tui").SettingsListTheme { +export function getSettingsListTheme(themeOverride?: Theme): import("@mariozechner/pi-tui").SettingsListTheme { + const t = themeOverride ?? theme; return { - label: (text: string, selected: boolean) => (selected ? theme.fg("accent", text) : text), - value: (text: string, selected: boolean) => (selected ? theme.fg("accent", text) : theme.fg("muted", text)), - description: (text: string) => theme.fg("dim", text), - cursor: theme.fg("accent", "→ "), - hint: (text: string) => theme.fg("dim", text), + label: (text: string, selected: boolean) => (selected ? t.fg("accent", text) : text), + value: (text: string, selected: boolean) => (selected ? t.fg("accent", text) : t.fg("muted", text)), + description: (text: string) => t.fg("dim", text), + cursor: t.fg("accent", "→ "), + hint: (text: string) => t.fg("dim", text), }; }