feat(shell): frameless window chrome + custom titlebar + theming#390
Open
patschmittdev wants to merge 1 commit into
Open
feat(shell): frameless window chrome + custom titlebar + theming#390patschmittdev wants to merge 1 commit into
patschmittdev wants to merge 1 commit into
Conversation
Split the feature-independent app-chrome out of feat/webgl-ambient-background onto the ui-foundation base. This is the shell window-frame + theming layer, without the AppShell/ViewRouter/ActivityBar feature-mount wiring (that is the final integration step once the feature branches land). - AppTitlebar: custom in-renderer titlebar (min/max/close + theme toggle) for the frameless Windows window; macOS keeps native traffic lights - main.ts / ipc/mind.ts: frameless BrowserWindow on non-mac (frame:false, white background, app menu hidden); window controls act on the sender window (fixes popout close-to-tray); set-theme IPC (no-op, renderer-driven titlebar) - sessionSecurity: inline theme-init <script> allowed by exact sha256 hash (INVARIANT-pinned by a test that recomputes it against index.html), so the pre-paint theme resolve doesn't trip the CSP. Voice CSP/permission lives on the voice branch; only the theme hash is here. - index.html: pre-paint theme-init script (no light/dark flash) - store: AppState.previousView + lifecycleReducer lens back-button (+ 4 tests) - preload/env: desktop.setTheme + desktop.window typing - polish: AuthScreen, A2ARelayView Shared-infra (idempotent, also on feat/ambient-canvas): tsconfig.base module commonjs -> esnext so the theme-hash test's import.meta.url type-checks. Scope notes: MindSidebar is intentionally NOT included -- its final state pulls in chatroom-session creation + agent accent color, so it belongs to the integration step, not chrome. The AppShell/ViewRouter/ActivityBar feature mounts (AmbientCanvas/ChatroomSessionPanel/UpdateBanner/AddAgentsView/UpdateIndicator) are the documented final reconciliation when all branches merge. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This was referenced Jun 22, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
The shell window-frame + theming chrome layer, split off
feat/webgl-ambient-backgroundonto therefactor/ui-foundationbase (#389). Stacks as a sibling of voice (#387) and ambient (#386).Contents (15 files, +356/-52)
Custom titlebar
AppTitlebar.tsx(new, +169): in-renderer min/max/close + animated day/night toggle for the frameless Windows window. macOS keeps native traffic lights.Frameless window + window controls
main.ts:frame:falseon non-mac (white bg, app menu hidden); window controls act on the sender window (fixes popout close-to-tray);set-themeIPC (no-op, renderer-driven).ipc/mind.ts,preload.ts,ipc-channels.ts,env.d.ts:desktop.window(minimize/maximize/close) +desktop.setThemetyping and channels.No-flash theming
index.html: pre-paint theme-init<script>resolves stored/system theme before first paint.sessionSecurity.ts: CSPscript-srcallowlists that inline script by exact sha256 hash. Security note for review: this is the only CSP change; it is scoped to the theme hash and is INVARIANT-pinned bysessionSecurity.test.ts, which recomputes the hash againstindex.html(any drift fails the test). Voice CSP stays on the voice branch.Store
lifecycleReducer+state.ts:previousViewfor the lens back-button (+ tests).Polish:
AuthScreen,A2ARelayView.Intentional: mount wiring deferred
AppTitlebaris not mounted inAppShellhere. TheAppShell/ViewRouter/ActivityBarfeature-mounts (AmbientCanvas / ChatroomSessionPanel / UpdateBanner / titlebar / ...) are the documented final reconciliation once the verticals land, soAppShelldoes not become a conflict magnet across every sibling slice.Stack
Validation
npm run lint-- green (tsc, eslint, dependency-cruiser 521 modules / 0 violations, yaml, md).sessionSecurity.test.tsCSP-hash invariant + lifecyclereducer.test.ts).