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
This commit is contained in:
Mario Zechner 2026-01-04 18:39:00 +01:00
parent 6390ff87ef
commit c447e62662
2 changed files with 17 additions and 24 deletions

View file

@ -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") {

View file

@ -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),
};
}