diff --git a/frontend/src/components/editor/CompilationConsole.tsx b/frontend/src/components/editor/CompilationConsole.tsx index 2c1bc666..18a2f14f 100644 --- a/frontend/src/components/editor/CompilationConsole.tsx +++ b/frontend/src/components/editor/CompilationConsole.tsx @@ -75,6 +75,12 @@ export const CompilationConsole: React.FC = ({ ⚠ {warningCount} )} + {/* Pro overlay mounts a "Diagnose with AI" button here when + errorCount > 0. Empty in the OSS image — slotMounter + only fires when the pro tree is present. */} + {errorCount > 0 && ( +
+ )}
diff --git a/frontend/src/pages/EditorPage.tsx b/frontend/src/pages/EditorPage.tsx index 4e335f2c..474acd36 100644 --- a/frontend/src/pages/EditorPage.tsx +++ b/frontend/src/pages/EditorPage.tsx @@ -27,6 +27,7 @@ import { LoginPromptModal } from '../components/layout/LoginPromptModal'; import { GitHubStarBanner } from '../components/layout/GitHubStarBanner'; import { useSimulatorStore, DEFAULT_BOARD_POSITION } from '../store/useSimulatorStore'; import { useEditorStore } from '../store/useEditorStore'; +import { useCompileLogsStore } from '../store/useCompileLogsStore'; import { useOscilloscopeStore } from '../store/useOscilloscopeStore'; import { useAuthStore } from '../store/useAuthStore'; import { useProjectStore } from '../store/useProjectStore'; @@ -81,7 +82,11 @@ export const EditorPage: React.FC = () => { const isRaspberryPi3 = activeBoardKind === 'raspberry-pi-3'; const oscilloscopeOpen = useOscilloscopeStore((s) => s.open); const [consoleOpen, setConsoleOpen] = useState(false); - const [compileLogs, setCompileLogs] = useState([]); + // compileLogs live in a Zustand store so the velxio-pro agent overlay + // (mounted in a separate React tree via slotMounter) can subscribe and + // build a "diagnose this failure" prompt without prop-drilling. + const compileLogs = useCompileLogsStore((s) => s.logs); + const setCompileLogs = useCompileLogsStore((s) => s.setLogs); const [bottomPanelHeight, setBottomPanelHeight] = useState(BOTTOM_PANEL_DEFAULT); const [saveModalOpen, setSaveModalOpen] = useState(false); const [loginPromptOpen, setLoginPromptOpen] = useState(false); diff --git a/frontend/src/store/useCompileLogsStore.ts b/frontend/src/store/useCompileLogsStore.ts new file mode 100644 index 00000000..b7a0925e --- /dev/null +++ b/frontend/src/store/useCompileLogsStore.ts @@ -0,0 +1,42 @@ +/** + * Zustand store for the editor's compile output. + * + * Lives outside so other components (notably the velxio-pro + * agent overlay, mounted into a different React tree via slotMounter) can + * subscribe without prop-drilling. The overlay reads `logs` to build a + * "diagnose this compile failure with AI" prompt; without the store it + * would have no way to reach the upstream component state. Board target + * is read from `useEditorStore` by the overlay independently. + */ + +import { create } from 'zustand'; + +import type { CompilationLog } from '../utils/compilationLogger'; + +/** React-style setter — accepts either a new value OR an updater fn so + * callers that used `useState`'s `setX(prev => ...)` form can be + * swapped in without rewriting the call sites. */ +type LogsSetter = ( + next: CompilationLog[] | ((prev: CompilationLog[]) => CompilationLog[]), +) => void; + +interface CompileLogsState { + logs: CompilationLog[]; + setLogs: LogsSetter; + appendLogs: (logs: CompilationLog[]) => void; + clear: () => void; +} + +export const useCompileLogsStore = create((set, get) => ({ + logs: [], + setLogs: (next) => { + if (typeof next === 'function') { + set({ logs: (next as (prev: CompilationLog[]) => CompilationLog[])(get().logs) }); + } else { + set({ logs: next }); + } + }, + appendLogs: (entries) => + set((s) => ({ logs: [...s.logs, ...entries] })), + clear: () => set({ logs: [] }), +}));