Files
openchamber/packages/ui/src/main.tsx
T

118 lines
4.0 KiB
TypeScript

import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import './styles/fonts'
import './index.css'
import App from './App.tsx'
import { SessionAuthGate } from './components/auth/SessionAuthGate'
import { ThemeSystemProvider } from './contexts/ThemeSystemContext'
import { ThemeProvider } from './components/providers/ThemeProvider'
import './lib/debug'
import { syncDesktopSettings, initializeAppearancePreferences } from './lib/persistence'
import { startAppearanceAutoSave } from './lib/appearanceAutoSave'
import { applyPersistedDirectoryPreferences } from './lib/directoryPersistence'
import { startTypographyWatcher } from './lib/typographyWatcher'
import type { RuntimeAPIs } from './lib/api/types'
declare global {
interface Window {
__OPENCHAMBER_RUNTIME_APIS__?: RuntimeAPIs;
}
}
const runtimeAPIs = (typeof window !== 'undefined' && window.__OPENCHAMBER_RUNTIME_APIS__) || (() => {
throw new Error('Runtime APIs not provided for legacy UI entrypoint.');
})();
await syncDesktopSettings();
await initializeAppearancePreferences();
startAppearanceAutoSave();
startTypographyWatcher();
await applyPersistedDirectoryPreferences();
if (typeof window !== 'undefined') {
(window as { debugContextTokens?: () => void }).debugContextTokens = () => {
const sessionStore = (window as { __zustand_session_store__?: { getState: () => { currentSessionId?: string; messages: Map<string, { info: { role: string }; parts: { type: string }[] }[]>; sessionContextUsage: Map<string, unknown>; getContextUsage: (contextLimit: number, outputLimit: number) => unknown } } }).__zustand_session_store__;
if (!sessionStore) {
return;
}
const state = sessionStore.getState();
const currentSessionId = state.currentSessionId;
if (!currentSessionId) {
return;
}
const sessionMessages = state.messages.get(currentSessionId) || [];
const assistantMessages = sessionMessages.filter((m: { info: { role: string } }) => m.info.role === 'assistant');
if (assistantMessages.length === 0) {
return;
}
const lastMessage = assistantMessages[assistantMessages.length - 1];
const tokens = (lastMessage.info as { tokens?: { input?: number; output?: number; reasoning?: number; cache?: { read?: number; write?: number } } }).tokens;
if (tokens && typeof tokens === 'object') {
console.debug('Token breakdown:', {
base: (tokens.input || 0) + (tokens.output || 0) + (tokens.reasoning || 0),
cache: tokens.cache ? (tokens.cache.read || 0) + (tokens.cache.write || 0) : 0
});
}
void state.sessionContextUsage.get(currentSessionId);
const configStore = (window as { __zustand_config_store__?: { getState: () => { getCurrentModel: () => { limit?: { context?: number } } | null } } }).__zustand_config_store__;
if (configStore) {
const currentModel = configStore.getState().getCurrentModel();
const contextLimit = currentModel?.limit?.context || 0;
const outputLimit =
currentModel && currentModel.limit && typeof currentModel.limit === 'object'
? Math.max(((currentModel.limit as { output?: number }).output ?? 0), 0)
: 0;
if (contextLimit > 0) {
void state.getContextUsage(contextLimit, outputLimit);
}
}
};
}
const rootElement = document.getElementById('root');
if (!rootElement) {
throw new Error('Root element not found');
}
createRoot(rootElement).render(
<StrictMode>
<ThemeSystemProvider>
<ThemeProvider>
<SessionAuthGate>
<App apis={runtimeAPIs} />
</SessionAuthGate>
</ThemeProvider>
</ThemeSystemProvider>
</StrictMode>,
);
if (typeof window !== 'undefined') {
const markRendererReady = () => {
try {
window.opencodeDesktop?.markRendererReady?.();
} catch (error) {
console.warn('Failed to notify desktop runtime that renderer is ready:', error);
}
};
markRendererReady();
document.addEventListener('visibilitychange', () => {
if (document.visibilityState === 'visible') {
markRendererReady();
}
});
}