From 0606240e30683b9c23dc85cc769c163170e18302 Mon Sep 17 00:00:00 2001 From: ndycode <405533+ndycode@users.noreply.github.com> Date: Sun, 22 Mar 2026 09:39:42 +0800 Subject: [PATCH] refactor: extract backend category entry wrapper --- lib/codex-manager/backend-category-entry.ts | 187 ++++++++++++++++++++ lib/codex-manager/settings-hub.ts | 4 +- test/backend-category-entry.test.ts | 56 ++++++ 3 files changed, 246 insertions(+), 1 deletion(-) create mode 100644 lib/codex-manager/backend-category-entry.ts create mode 100644 test/backend-category-entry.test.ts diff --git a/lib/codex-manager/backend-category-entry.ts b/lib/codex-manager/backend-category-entry.ts new file mode 100644 index 00000000..87ff9b3b --- /dev/null +++ b/lib/codex-manager/backend-category-entry.ts @@ -0,0 +1,187 @@ +import type { PluginConfig } from "../types.js"; +import type { + BackendCategoryOption, + BackendNumberSettingKey, + BackendNumberSettingOption, + BackendSettingFocusKey, + BackendToggleSettingKey, + BackendToggleSettingOption, +} from "./backend-settings-schema.js"; + +export async function promptBackendCategorySettingsEntry(params: { + initial: PluginConfig; + category: BackendCategoryOption; + initialFocus: BackendSettingFocusKey; + promptBackendCategorySettingsMenu: (args: { + initial: PluginConfig; + category: BackendCategoryOption; + initialFocus: BackendSettingFocusKey; + ui: ReturnType; + cloneBackendPluginConfig: (config: PluginConfig) => PluginConfig; + buildBackendSettingsPreview: ( + config: PluginConfig, + ui: ReturnType, + focusKey: BackendSettingFocusKey, + deps: { + highlightPreviewToken: ( + text: string, + ui: ReturnType, + ) => string; + }, + ) => { label: string; hint: string }; + highlightPreviewToken: ( + text: string, + ui: ReturnType, + ) => string; + resolveFocusedBackendNumberKey: ( + focus: BackendSettingFocusKey, + numberOptions: BackendNumberSettingOption[], + ) => BackendNumberSettingKey; + clampBackendNumber: ( + option: BackendNumberSettingOption, + value: number, + ) => number; + formatBackendNumberValue: ( + option: BackendNumberSettingOption, + value: number, + ) => string; + formatDashboardSettingState: (enabled: boolean) => string; + applyBackendCategoryDefaults: ( + config: PluginConfig, + selectedCategory: BackendCategoryOption, + ) => PluginConfig; + getBackendCategoryInitialFocus: ( + category: BackendCategoryOption, + ) => BackendSettingFocusKey; + backendDefaults: PluginConfig; + toggleOptionByKey: ReadonlyMap< + BackendToggleSettingKey, + BackendToggleSettingOption + >; + numberOptionByKey: ReadonlyMap< + BackendNumberSettingKey, + BackendNumberSettingOption + >; + select: ( + items: import("../ui/select.js").MenuItem[], + options: { + message: string; + subtitle: string; + help: string; + clearScreen: boolean; + theme: ReturnType< + typeof import("../ui/runtime.js").getUiRuntimeOptions + >["theme"]; + selectedEmphasis: "minimal"; + initialCursor?: number; + onCursorChange: (event: { cursor: number }) => void; + onInput: (raw: string) => T | undefined; + }, + ) => Promise; + copy: { + previewHeading: string; + backendToggleHeading: string; + backendNumberHeading: string; + backendDecrease: string; + backendIncrease: string; + backendResetCategory: string; + backendBackToCategories: string; + backendCategoryTitle: string; + backendCategoryHelp: string; + }; + }) => Promise<{ draft: PluginConfig; focusKey: BackendSettingFocusKey }>; + ui: ReturnType; + cloneBackendPluginConfig: (config: PluginConfig) => PluginConfig; + buildBackendSettingsPreview: ( + config: PluginConfig, + ui: ReturnType, + focusKey: BackendSettingFocusKey, + deps: { + highlightPreviewToken: ( + text: string, + ui: ReturnType, + ) => string; + }, + ) => { label: string; hint: string }; + highlightPreviewToken: ( + text: string, + ui: ReturnType, + ) => string; + resolveFocusedBackendNumberKey: ( + focus: BackendSettingFocusKey, + numberOptions: BackendNumberSettingOption[], + ) => BackendNumberSettingKey; + clampBackendNumber: ( + option: BackendNumberSettingOption, + value: number, + ) => number; + formatBackendNumberValue: ( + option: BackendNumberSettingOption, + value: number, + ) => string; + formatDashboardSettingState: (enabled: boolean) => string; + applyBackendCategoryDefaults: ( + config: PluginConfig, + selectedCategory: BackendCategoryOption, + ) => PluginConfig; + getBackendCategoryInitialFocus: ( + category: BackendCategoryOption, + ) => BackendSettingFocusKey; + backendDefaults: PluginConfig; + toggleOptionByKey: ReadonlyMap< + BackendToggleSettingKey, + BackendToggleSettingOption + >; + numberOptionByKey: ReadonlyMap< + BackendNumberSettingKey, + BackendNumberSettingOption + >; + select: ( + items: import("../ui/select.js").MenuItem[], + options: { + message: string; + subtitle: string; + help: string; + clearScreen: boolean; + theme: ReturnType< + typeof import("../ui/runtime.js").getUiRuntimeOptions + >["theme"]; + selectedEmphasis: "minimal"; + initialCursor?: number; + onCursorChange: (event: { cursor: number }) => void; + onInput: (raw: string) => T | undefined; + }, + ) => Promise; + copy: { + previewHeading: string; + backendToggleHeading: string; + backendNumberHeading: string; + backendDecrease: string; + backendIncrease: string; + backendResetCategory: string; + backendBackToCategories: string; + backendCategoryTitle: string; + backendCategoryHelp: string; + }; +}): Promise<{ draft: PluginConfig; focusKey: BackendSettingFocusKey }> { + return params.promptBackendCategorySettingsMenu({ + initial: params.initial, + category: params.category, + initialFocus: params.initialFocus, + ui: params.ui, + cloneBackendPluginConfig: params.cloneBackendPluginConfig, + buildBackendSettingsPreview: params.buildBackendSettingsPreview, + highlightPreviewToken: params.highlightPreviewToken, + resolveFocusedBackendNumberKey: params.resolveFocusedBackendNumberKey, + clampBackendNumber: params.clampBackendNumber, + formatBackendNumberValue: params.formatBackendNumberValue, + formatDashboardSettingState: params.formatDashboardSettingState, + applyBackendCategoryDefaults: params.applyBackendCategoryDefaults, + getBackendCategoryInitialFocus: params.getBackendCategoryInitialFocus, + backendDefaults: params.backendDefaults, + toggleOptionByKey: params.toggleOptionByKey, + numberOptionByKey: params.numberOptionByKey, + select: params.select, + copy: params.copy, + }); +} diff --git a/lib/codex-manager/settings-hub.ts b/lib/codex-manager/settings-hub.ts index 072e2cac..a1baa02f 100644 --- a/lib/codex-manager/settings-hub.ts +++ b/lib/codex-manager/settings-hub.ts @@ -22,6 +22,7 @@ import { UI_COPY } from "../ui/copy.js"; import { getUiRuntimeOptions, setUiRuntimeOptions } from "../ui/runtime.js"; import { select } from "../ui/select.js"; import { sleep } from "../utils.js"; +import { promptBackendCategorySettingsEntry } from "./backend-category-entry.js"; import { applyBackendCategoryDefaults, getBackendCategory, @@ -587,10 +588,11 @@ async function promptBackendCategorySettings( category: BackendCategoryOption, initialFocus: BackendSettingFocusKey, ): Promise<{ draft: PluginConfig; focusKey: BackendSettingFocusKey }> { - return promptBackendCategorySettingsMenu({ + return promptBackendCategorySettingsEntry({ initial, category, initialFocus, + promptBackendCategorySettingsMenu, ui: getUiRuntimeOptions(), cloneBackendPluginConfig, buildBackendSettingsPreview, diff --git a/test/backend-category-entry.test.ts b/test/backend-category-entry.test.ts new file mode 100644 index 00000000..f87bd402 --- /dev/null +++ b/test/backend-category-entry.test.ts @@ -0,0 +1,56 @@ +import { describe, expect, it, vi } from "vitest"; +import { promptBackendCategorySettingsEntry } from "../lib/codex-manager/backend-category-entry.js"; + +describe("backend category entry", () => { + it("passes category wiring through to the backend category prompt helper", async () => { + const promptBackendCategorySettingsMenu = vi.fn(async () => ({ + draft: { fetchTimeoutMs: 1000 }, + focusKey: null, + })); + + const result = await promptBackendCategorySettingsEntry({ + initial: { fetchTimeoutMs: 2000 }, + category: { + key: "session-sync", + label: "Session Sync", + description: "desc", + } as never, + initialFocus: null, + promptBackendCategorySettingsMenu, + ui: { theme: {} } as never, + cloneBackendPluginConfig: vi.fn((config) => config), + buildBackendSettingsPreview: vi.fn(() => ({ + label: "Preview", + hint: "Hint", + })), + highlightPreviewToken: vi.fn((text) => text), + resolveFocusedBackendNumberKey: vi.fn(() => "fetchTimeoutMs" as never), + clampBackendNumber: vi.fn((_, value) => value), + formatBackendNumberValue: vi.fn((_, value) => String(value)), + formatDashboardSettingState: vi.fn((enabled) => (enabled ? "on" : "off")), + applyBackendCategoryDefaults: vi.fn((config) => config), + getBackendCategoryInitialFocus: vi.fn(() => null), + backendDefaults: { fetchTimeoutMs: 1000 }, + toggleOptionByKey: new Map(), + numberOptionByKey: new Map(), + select: vi.fn(), + copy: { + previewHeading: "Preview", + backendToggleHeading: "Toggles", + backendNumberHeading: "Numbers", + backendDecrease: "Decrease", + backendIncrease: "Increase", + backendResetCategory: "Reset", + backendBackToCategories: "Back", + backendCategoryTitle: "Category", + backendCategoryHelp: "Help", + }, + }); + + expect(promptBackendCategorySettingsMenu).toHaveBeenCalled(); + expect(result).toEqual({ + draft: { fetchTimeoutMs: 1000 }, + focusKey: null, + }); + }); +});