setOpen(false)}
aria-hidden="true"
/>
);
}
function MobileRightRailBackdrop() {
const { open, setOpen } = useRightRailDrawer();
const { isMobile } = useViewport();
if (!isMobile || !open) return null;
return (
setOpen(false)}
aria-hidden="true"
/>
);
}
function AppShell() {
// themes-v1: useTheme() owns the matchMedia subscription for system mode
// and reconciles cache with /api/settings on mount. Mounted first so the
// theme class on is correct before any child renders.
useTheme();
useUserEvents();
useCoderUserEvents();
useEffect(() => {
const unsub = sessionEvents.subscribe((event) => {
if (event.type === 'collision_warning') {
toast.warning(`Multiple agents editing ${event.file_path}`, {
description: `Agents: ${event.agents.join(', ')}`,
});
} else if (event.type === 'agent_message') {
const truncated =
event.content.length > 80
? event.content.slice(0, 80) + '…'
: event.content;
toast.info(`Message from ${event.from_agent}`, {
description: truncated,
});
}
});
return unsub;
}, []);
const [showShortcuts, setShowShortcuts] = useState(false);
useEffect(() => {
const handler = (e: KeyboardEvent) => {
if (e.key === '?' && !e.metaKey && !e.ctrlKey && !e.altKey) {
const tag = (e.target as HTMLElement)?.tagName;
if (tag !== 'INPUT' && tag !== 'TEXTAREA' && !(e.target as HTMLElement)?.isContentEditable) {
setShowShortcuts((v) => !v);
}
}
};
window.addEventListener('keydown', handler);
return () => window.removeEventListener('keydown', handler);
}, []);
// v1.10.8c: h-dvh (dynamic viewport) instead of h-screen (100vh) so the
// root height excludes the iOS URL-bar overlay area. Without this, every
// descendant — including the terminal pane — measures itself against a
// height that extends behind the URL bar, and xterm allocates extra rows
// that scroll out of reach on iPhone.
//
// ThemeFx: canvas-based animated backgrounds (Classic rain, Override neon
// field) rendered at z-0 behind the content wrapper. ThemeFx also manages
// the bc-anim-on gate class on . Content wrapper at z-10 ensures all
// UI sits above any fixed canvas regardless of theme.
return (
<>
} />
} />
} />
} />
} />
} />
} />
} />
>
);
}
export default function App() {
return (
);
}