#22361: fix(macos/canvas): prevent A2UI reload loop and add A2UI MIME mapping
app: macos
size: S
Cluster:
Gateway Resilience and Configuration
## Summary
- Update macOS canvas auto-navigation logic so `shouldAutoNavigateToA2UI(lastAutoTarget:)` returns `false` when the current target already equals the last auto-navigation target, preventing immediate reload loops that wipe freshly rendered A2UI content.
- Add extension-based MIME mapping for A2UI static files in `src/canvas-host/a2ui.ts` so `.js`, `.css`, `.json`, and `.map` always get browser-friendly content types before content-sniffing.
- Add canvas-host test coverage for these MIME mappings in `src/canvas-host/server.test.ts`.
## Why this fixes the issue
These changes stop redundant forced reloads from auto-navigation and ensure A2UI assets are served in executable formats that browsers can parse, so rendered content persists instead of flashing and disappearing.
## Tests
- `pnpm vitest run src/canvas-host/server.test.ts`
- `pnpm vitest run src/canvas-host/*.test.ts`
## Edge cases considered
- A2UI HTML files continue to be served with `text/html; charset=utf-8` and live-reload script injection.
- Unknown extensions still fall back to existing `detectMime(...)` behavior.
- HEAD requests preserve the selected Content-Type header for each path.
<!-- greptile_comment -->
<h3>Greptile Summary</h3>
Fixed A2UI reload loop and added MIME type mappings for static assets. The Swift change inverted the logic in `shouldAutoNavigateToA2UI` to prevent auto-navigation when the target hasn't changed (returning `false` instead of `true` when `trimmed == lastAuto`), stopping redundant reloads. The TypeScript changes added explicit MIME type mappings for `.js`, `.css`, `.json`, and `.map` files before falling back to content sniffing, ensuring browsers receive correct content types for A2UI assets.
**Key changes:**
- `CanvasWindowController.swift:369` - return `false` (was `true`) when current target equals last auto-nav target
- `a2ui.ts` - added `A2UI_MIME_BY_EXT` lookup table with charset-utf-8 for common web file extensions
- `a2ui.ts:208` - changed condition from exact match (`mime === "text/html"`) to prefix check (`mime.startsWith("text/html")`) to handle charset variants
- `server.test.ts` - added comprehensive test coverage for all four MIME mappings
<h3>Confidence Score: 5/5</h3>
- This PR is safe to merge with minimal risk
- The changes are well-scoped, logically correct, and include test coverage. The Swift logic fix correctly prevents reload loops by inverting a boolean return when targets match. The MIME type mappings follow web standards and have explicit fallbacks. The test validates all four new MIME mappings with proper cleanup.
- No files require special attention
<sub>Last reviewed commit: ad53db0</sub>
<!-- greptile_other_comments_section -->
<!-- /greptile_comment -->
Most Similar PRs
#16037: fix(canvas): resolve A2UI assets from dist + retry resolution
by AlexAnys · 2026-02-14
74.8%
#7852: fix(gateway): use port from Host header for canvasHostUrl (reverse ...
by tonimelisma · 2026-02-03
72.5%
#21667: fix(canvas): add CSP and security headers to HTML responses
by AI-Reviewer-QS · 2026-02-20
72.0%
#10257: fix(security): anchor MIME sanitization regex and block fullwidth b...
by nu-gui · 2026-02-06
71.5%
#2544: fix(security): XSS vulnerability in Canvas Host + Windows CI stability
by Kiwitwitter · 2026-01-27
69.6%
#11160: Media: add missing audio MIME-to-extension mappings (aac, flac, opu...
by lailoo · 2026-02-07
68.6%
#20843: docs: add troubleshooting for A2UI bundling and missing node_modules
by yahiag04 · 2026-02-19
68.5%
#16480: fix(build): replace bash A2UI bundle script with cross-platform Typ...
by colddonkey · 2026-02-14
68.2%
#17286: fix(media): PDF attachments embedded as raw binary instead of extra...
by yinghaosang · 2026-02-15
67.9%
#8261: fix: enable A2UI Canvas on remote gateways
by rothnic · 2026-02-03
67.8%