Skip to content

Commit 82f8234

Browse files
committed
fix: frontend review fixes from codex audit
- termwrap: declare claudeCodeActiveAtom on TermWrap class (was used in osc-handlers and term-model but never declared, would crash at runtime) - termwrap: apply computed isCC to claudeCodeActiveAtom on rtInfo load (was computed but never stored, leaving atom stale after reconnect) - tabbar: replace createRef with useRef for widgetsSidebarButtonRef (createRef in function component creates new object every render) - app/preload: expose offNativeThemeChange to enable useEffect cleanup in AppAutoThemeUpdater, preventing ipc listener accumulation on autoTheme toggle
1 parent f6fefad commit 82f8234

5 files changed

Lines changed: 17 additions & 8 deletions

File tree

emain/preload.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,13 @@ contextBridge.exposeInMainWorld("api", {
7373
saveTextFile: (fileName: string, content: string) => ipcRenderer.invoke("save-text-file", fileName, content),
7474
setIsActive: () => ipcRenderer.invoke("set-is-active"),
7575
getNativeThemeIsDark: () => ipcRenderer.sendSync("get-native-theme") as boolean,
76-
onNativeThemeChange: (callback: (isDark: boolean) => void) =>
77-
ipcRenderer.on("native-theme-change", (_event, isDark: boolean) => callback(isDark)),
76+
onNativeThemeChange: (callback: (isDark: boolean) => void) => {
77+
const wrapped = (_event: Electron.IpcRendererEvent, isDark: boolean) => callback(isDark);
78+
ipcRenderer.on("native-theme-change", wrapped);
79+
return wrapped;
80+
},
81+
offNativeThemeChange: (wrapped: (event: Electron.IpcRendererEvent, isDark: boolean) => void) =>
82+
ipcRenderer.removeListener("native-theme-change", wrapped),
7883
});
7984

8085
// Custom event for "new-window"

frontend/app/app.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -211,16 +211,16 @@ function AppAutoThemeUpdater() {
211211
if (!api?.getNativeThemeIsDark || !api?.onNativeThemeChange) {
212212
return;
213213
}
214-
// no-op: theme is read-only in this component; actual term theme switching
215-
// is handled by listening for the OS theme change event and posting it
216-
// as a custom DOM event that TermThemeUpdater can react to.
217214
const handler = (isDark: boolean) => {
218215
const themeName = isDark ? "default-dark" : "default-light";
219216
document.body.dispatchEvent(new CustomEvent("wave:os-theme-change", { detail: { themeName } }));
220217
};
221-
api.onNativeThemeChange(handler);
218+
const wrapped = api.onNativeThemeChange(handler);
222219
// trigger immediately on mount
223220
handler(api.getNativeThemeIsDark());
221+
return () => {
222+
api.offNativeThemeChange?.(wrapped);
223+
};
224224
}, [autoTheme]);
225225

226226
return null;

frontend/app/tab/tabbar.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ const TabBar = memo(({ workspace, noTabs }: TabBarProps) => {
147147
const rightContainerRef = useRef<HTMLDivElement>(null);
148148
const workspaceSwitcherRef = useRef<HTMLDivElement>(null);
149149
const waveAIButtonRef = useRef<HTMLDivElement>(null);
150-
const widgetsSidebarButtonRef = createRef<HTMLDivElement>();
150+
const widgetsSidebarButtonRef = useRef<HTMLDivElement>(null);
151151
const appMenuButtonRef = useRef<HTMLDivElement>(null);
152152
const tabWidthRef = useRef<number>(TabDefaultWidth);
153153
const scrollableRef = useRef<boolean>(false);

frontend/app/view/term/termwrap.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ export class TermWrap {
100100
lastCmdExitCodeAtom: jotai.PrimitiveAtom<number | null>;
101101
shellInputBufferAtom: jotai.PrimitiveAtom<string | null>;
102102
shellInputCursorAtom: jotai.PrimitiveAtom<number | null>;
103+
claudeCodeActiveAtom: jotai.PrimitiveAtom<boolean>;
103104
nodeModel: BlockNodeModel; // this can be null
104105
hoveredLinkUri: string | null = null;
105106
onLinkHover?: (uri: string | null, mouseX: number, mouseY: number) => void;
@@ -142,6 +143,7 @@ export class TermWrap {
142143
this.lastCmdExitCodeAtom = jotai.atom(null) as jotai.PrimitiveAtom<number | null>;
143144
this.shellInputBufferAtom = jotai.atom(null) as jotai.PrimitiveAtom<string | null>;
144145
this.shellInputCursorAtom = jotai.atom(null) as jotai.PrimitiveAtom<number | null>;
146+
this.claudeCodeActiveAtom = jotai.atom(false) as jotai.PrimitiveAtom<boolean>;
145147
this.webglEnabledAtom = jotai.atom(false) as jotai.PrimitiveAtom<boolean>;
146148
this.terminal = new Terminal(options);
147149
this.fitAddon = new FitAddon();
@@ -414,6 +416,7 @@ export class TermWrap {
414416

415417
const lastCmd = rtInfo ? rtInfo["shell:lastcmd"] : null;
416418
const isCC = shellState === "running-command" && isClaudeCodeCommand(lastCmd);
419+
globalStore.set(this.claudeCodeActiveAtom, isCC);
417420
globalStore.set(this.lastCommandAtom, lastCmd || null);
418421
const inputBuffer64 = rtInfo ? rtInfo["shell:inputbuffer64"] : null;
419422
if (inputBuffer64 == null) {

frontend/types/custom.d.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,8 @@ declare global {
136136
saveTextFile: (fileName: string, content: string) => Promise<boolean>; // save-text-file
137137
setIsActive: () => Promise<void>; // set-is-active
138138
getNativeThemeIsDark: () => boolean; // get-native-theme
139-
onNativeThemeChange: (callback: (isDark: boolean) => void) => void; // native-theme-change
139+
onNativeThemeChange: (callback: (isDark: boolean) => void) => (event: unknown, isDark: boolean) => void; // native-theme-change
140+
offNativeThemeChange: (wrapped: (event: unknown, isDark: boolean) => void) => void; // native-theme-change off
140141
};
141142

142143
type ElectronContextMenuItem = {

0 commit comments

Comments
 (0)