2026-04-05 Session: Convert AI chat from sheet to dedicated window per article

What was done

  • Converted AI chat from a modal sheet to a dedicated macOS window per article, allowing multiple chats open simultaneously and free repositioning
  • Created ArticleAIChatWindowManager following the existing AppLogWindowManager pattern, tracking one window per article UUID
  • Added 20px bottom padding to chat messages for visual comfort
  • Auto-focus the input field when the chat window opens, using @FocusState on macOS 13+ with graceful fallback
  • Updated CLAUDE.md with guideline to use #available/@available for newer APIs while maintaining macOS 12 compatibility

Key decisions

  • Used the direct NSWindow + NSHostingView pattern (like AppLogWindowManager) rather than the heavier WindowManager/WindowController/Window/ViewController hierarchy — simplest approach that supports multiple instances
  • Replaced @Environment(\.dismiss) with NSApp.keyWindow?.close() since dismiss doesn't work outside sheet context
  • For auto-focus, extracted a FocusableChatInput struct gated behind @available(macOS 13.0, *) rather than using fragile NSView hierarchy traversal

Files changed

  • Planet/Views/Articles/ArticleAIChatWindowManager.swift — New file: window manager tracking one NSWindow per article UUID
  • Planet/Views/Articles/ArticleView.swift — Removed sheet presentation, toolbar button now opens dedicated window
  • Planet/Views/Articles/ArticleAIChatView.swift — Removed dismiss environment, replaced with window close, flexible frame, bottom padding, focusOnAppear
  • Planet/Views/Articles/ChatInputField.swift — Added focusOnAppear support with @FocusState on macOS 13+
  • Planet.xcodeproj/project.pbxproj — Added new file to Planet target
  • CLAUDE.md — Added #available API adoption guideline