feat(coding-agent): add automatic theme mode (#5874)
This commit is contained in:
@@ -151,6 +151,13 @@ describe("InteractiveMode.createExtensionUIContext setTheme", () => {
|
||||
const fakeThis: any = {
|
||||
session: { settingsManager },
|
||||
settingsManager,
|
||||
themeController: {
|
||||
setThemeInstance: vi.fn(() => ({ success: true })),
|
||||
setThemeName: vi.fn(() => {
|
||||
fakeThis.ui.requestRender();
|
||||
return { success: true };
|
||||
}),
|
||||
},
|
||||
ui: { requestRender: vi.fn() },
|
||||
};
|
||||
|
||||
@@ -158,6 +165,7 @@ describe("InteractiveMode.createExtensionUIContext setTheme", () => {
|
||||
const result = uiContext.setTheme("light");
|
||||
|
||||
expect(result.success).toBe(true);
|
||||
expect(fakeThis.themeController.setThemeName).toHaveBeenCalledWith("light");
|
||||
expect(settingsManager.setTheme).toHaveBeenCalledWith("light");
|
||||
expect(currentTheme).toBe("light");
|
||||
expect(fakeThis.ui.requestRender).toHaveBeenCalledTimes(1);
|
||||
@@ -173,6 +181,10 @@ describe("InteractiveMode.createExtensionUIContext setTheme", () => {
|
||||
const fakeThis: any = {
|
||||
session: { settingsManager },
|
||||
settingsManager,
|
||||
themeController: {
|
||||
setThemeInstance: vi.fn(() => ({ success: true })),
|
||||
setThemeName: vi.fn(() => ({ success: false, error: "Theme not found" })),
|
||||
},
|
||||
ui: { requestRender: vi.fn() },
|
||||
};
|
||||
|
||||
@@ -180,6 +192,7 @@ describe("InteractiveMode.createExtensionUIContext setTheme", () => {
|
||||
const result = uiContext.setTheme("__missing_theme__");
|
||||
|
||||
expect(result.success).toBe(false);
|
||||
expect(fakeThis.themeController.setThemeName).toHaveBeenCalledWith("__missing_theme__");
|
||||
expect(settingsManager.setTheme).not.toHaveBeenCalled();
|
||||
expect(fakeThis.ui.requestRender).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
@@ -198,6 +198,24 @@ describe("SettingsManager", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("theme setting", () => {
|
||||
it("stores slash-separated automatic theme settings separately from fixed theme names", async () => {
|
||||
const settingsPath = join(agentDir, "settings.json");
|
||||
writeFileSync(settingsPath, JSON.stringify({ theme: "light/dark" }));
|
||||
|
||||
const manager = SettingsManager.create(projectDir, agentDir);
|
||||
|
||||
expect(manager.getTheme()).toBeUndefined();
|
||||
expect(manager.getThemeSetting()).toBe("light/dark");
|
||||
|
||||
manager.setTheme("solarized-light/tokyo-night");
|
||||
await manager.flush();
|
||||
|
||||
const savedSettings = JSON.parse(readFileSync(settingsPath, "utf-8"));
|
||||
expect(savedSettings.theme).toBe("solarized-light/tokyo-night");
|
||||
});
|
||||
});
|
||||
|
||||
describe("error tracking", () => {
|
||||
it("should collect and clear load errors via drainErrors", () => {
|
||||
const globalSettingsPath = join(agentDir, "settings.json");
|
||||
|
||||
@@ -21,6 +21,7 @@ type ShutdownThis = {
|
||||
unregisterSignalHandlers: () => void;
|
||||
runtimeHost: { dispose: () => Promise<void> };
|
||||
ui: { terminal: { drainInput: (ms: number) => Promise<void> } };
|
||||
themeController: { disableAutoSync: () => void };
|
||||
stop: () => void;
|
||||
sessionManager: SessionManager;
|
||||
};
|
||||
@@ -81,6 +82,7 @@ function createContext(order: string[], sessionManager = createSessionManager())
|
||||
}),
|
||||
},
|
||||
},
|
||||
themeController: { disableAutoSync: vi.fn() },
|
||||
stop: vi.fn(() => {
|
||||
order.push("stop");
|
||||
}),
|
||||
|
||||
@@ -13,6 +13,7 @@ type ShutdownThis = {
|
||||
unregisterSignalHandlers: () => void;
|
||||
runtimeHost: { dispose: () => Promise<void> };
|
||||
ui: { terminal: { drainInput: (ms: number) => Promise<void> } };
|
||||
themeController: { disableAutoSync: () => void };
|
||||
stop: () => void;
|
||||
};
|
||||
|
||||
@@ -73,6 +74,7 @@ describe("InteractiveMode SIGTERM shutdown with signal-exit (#5724)", () => {
|
||||
}),
|
||||
},
|
||||
},
|
||||
themeController: { disableAutoSync: vi.fn() },
|
||||
stop: vi.fn(() => {
|
||||
order.push("stop");
|
||||
}),
|
||||
|
||||
@@ -5,6 +5,8 @@ import {
|
||||
detectTerminalBackgroundTheme,
|
||||
getThemeByName,
|
||||
getThemeForRgbColor,
|
||||
parseAutoThemeSetting,
|
||||
resolveThemeSetting,
|
||||
} from "../src/modes/interactive/theme/theme.ts";
|
||||
|
||||
afterEach(() => {
|
||||
@@ -119,3 +121,13 @@ describe("theme detection from RGB", () => {
|
||||
expect(getThemeForRgbColor({ r: 250, g: 250, b: 250 })).toBe("light");
|
||||
});
|
||||
});
|
||||
|
||||
describe("theme setting helpers", () => {
|
||||
it("parses and resolves automatic theme settings", () => {
|
||||
expect(parseAutoThemeSetting("light/dark")).toEqual({ lightTheme: "light", darkTheme: "dark" });
|
||||
expect(resolveThemeSetting("dark", "light")).toBe("dark");
|
||||
expect(resolveThemeSetting("light/dark", "light")).toBe("light");
|
||||
expect(resolveThemeSetting("light/dark", "dark")).toBe("dark");
|
||||
expect(resolveThemeSetting("light/dark/extra", "dark")).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user