Wire Finder open as a standard document open

application(_:open:) forwards every Finder-delivered URL to
AppModel.openBoard(at:) — the exact path welcome and File > Open use, so
a Finder open gets the same registry record-before-load, recents stamp,
already-open-focuses-its-window dedup, and row-level failure surfacing
on welcome (DESIGN/02 > Launch). A cold Finder launch can arrive before
any scene has captured the window opener; openBoard now buffers such
URLs and captureWindowActions replays them once opening is possible.

Claude-Session: https://claude.ai/code/session_01SR4XGjmBE16ZUYWpfFHXwY
This commit is contained in:
2026-07-28 07:09:44 -04:00
parent ac5ac4c2cd
commit cc4cc99c71
2 changed files with 44 additions and 1 deletions
+25
View File
@@ -34,6 +34,31 @@ final class AppDelegate: NSObject, NSApplicationDelegate {
return false
}
/// Double-clicking a `.kanban` folder in Finder, or `open -a` "opening a board from Finder is a
/// standard document open" (02-architecture.md § Launch and window lifecycle). Every URL is
/// forwarded to `AppModel.openBoard(at:)`, the exact entry point welcome and File Open already
/// call (`AppModel.presentOpenPanel()`), so a Finder open gets the identical registry record,
/// board window, and recents stamp, and a board that is already open focuses its window rather
/// than opening a second one `openBoard` starts its own security-scoped access on the URL, the
/// same as the open panel's, so nothing needs stashing here first.
///
/// **Not pre-validated.** Info.plist's `CFBundleDocumentTypes` declares the UTI, so macOS should
/// never route anything but a `.kanban` folder here but if it did, or the folder has since gone
/// missing, `openBoard`'s fail-fast load surfaces the failure row-level on welcome, uniform with
/// every other open failure. A second vocabulary for "not a board" here would just be a worse copy
/// of the one that already exists.
///
/// **Can fire before any scene has appeared** a cold launch (the app was not already running)
/// delivers this ahead of the first window's `onAppear`, which is where `windowOpener` is normally
/// captured (`CaptureOpenWindow`). `openBoard` buffers a URL that arrives that early and replays
/// it once the action exists, so this method does not have to reason about launch ordering itself.
func application(_ application: NSApplication, open urls: [URL]) {
guard let appModel else { return }
for url in urls {
appModel.openBoard(at: url)
}
}
/// Quit runs the close flush for **every** open board before the app goes away.
///
/// The same `CloseFlushCoordinator` sequence as a user close, once per board, in the same fixed