Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion BRIEFING.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@
- Preview patching keyed by pre-enhancement block hashes in a WeakMap (KaTeX/Mermaid mutate rendered nodes in place, so live DOM never equals fresh parser output); diff is common prefix/suffix, middle run replaced; mermaid sources stashed in dataset.bpSrc so theme switches can re-render processed diagrams.
- Workspace access control: allowed_dirs holds canonicalized folders; a path passes only if its canonicalized form sits under a granted dir (non-canonicalizable paths never dir-match, blocking .. and dangling-symlink rides). Recents-based grants flow through open_tracked_file, which also keeps open_windows/session/recents tracking correct for in-window switches.
- Session list is an ordered Vec under pref_lock; quitting sets a QUITTING flag (RunEvent::ExitRequested) so windows closed by quit keep their session entries.
- Startup windows resolve in resolve_startup_windows on RunEvent::Ready, not in setup: tao/tauri forward macOS openURLs-vs-didFinishLaunching order verbatim (no buffering), so a setup-time welcome fallback raced RunEvent::Opened and left a stray empty window on a Finder double-click. CLI/argv launches still open in setup (had_cli_args makes the resolver skip session restore). The welcome window's label is armed (startup_blank_label); a launch Opened reclaims it only while still pristine (label not a value in open_windows), so a document-bearing window is never closed. This is ordering-independent; a sub-second welcome flash is possible only if macOS delivers the file after launch finishes.
- Startup windows resolve in resolve_startup_windows on RunEvent::Ready, not in setup: tao/tauri forward macOS openURLs-vs-didFinishLaunching order verbatim (no buffering), so a setup-time welcome fallback raced RunEvent::Opened and left a stray empty window on a Finder double-click. CLI/argv launches still open in setup (had_cli_args makes the resolver skip session restore). The welcome window's label is armed (startup_blank_label); a launch Opened reclaims it only while still pristine (label not a value in open_windows), so a document-bearing window is never closed. This is ordering-independent; a sub-second welcome flash is possible only if macOS delivers the file after launch finishes. resolve_startup_windows waits STARTUP_OPENED_GRACE_MS (100ms) after Ready, then if startup_opened_file is set (a Launch Services / Finder file double-click launch) returns early: skips session restore and welcome so a cold-start file-open shows ONLY the clicked file. Plain app-icon launch (no Opened) restores the saved session; CLI launch skips both via had_cli_args before the delay.
- Preference store contract: the map may hold any subset of keys (save_preference_key writes one at a time), so AppPreferences carries #[serde(default)]; a partial map must never reset preferences.
- Release DMGs are renamed in release.yml to BoltPage-<ver>-arm64.dmg / BoltPage-<ver>-x64.dmg so GitHub assets match the Homebrew cask URLs.
- Windows CI signing is real: release.yml imports the PFX secret, reads its thumbprint, and injects bundle.windows.certificateThumbprint at build time (committed config stays unsigned so local dev builds work); builds are unsigned only when the secret is absent.
Expand Down
4 changes: 4 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,3 +118,7 @@ Format: `YYYY-MM-DD [type] description` (max 200 chars). Types: decision, plan,
2026-06-24 [code] Ordering-independent resolver: AppState gains had_cli_args/startup_opened_file/startup_blank_label; CLI launch stays in setup; Ready restores session + welcome fallback; a launch Opened reclaims the welcome window only while still pristine (label absent from open_windows), so no document window is ever closed.
2026-06-24 [note] Version bumped 2.2.2->2.2.3; local unsigned build (BoltPage.app + BoltPage_2.2.3_aarch64.dmg in target/release/bundle/) for testing the RunEvent::Ready startup-window fix.
2026-06-24 [note] tauri reads tauri.conf.json before beforeBuildCommand syncs it, so a package.json-only bump leaves the first local bundle's metadata a version behind. Build twice or pre-run sync-version.sh.
2026-06-24 [note] v2.2.3 released: dev->main via PR #32 (CI-gated), lightweight tag v2.2.3; release run 28119446748 published public Release (arm64/x64 DMG + x64 setup). v2.2.2 never committed, skipped.
2026-06-24 [code] Homebrew cask bumped 2.2.1->2.2.3 with real sha256 for both DMGs (update-cask.sh) and pushed to Silverfell/homebrew-tap.
2026-06-29 [code] resolve_startup_windows skips session restore on Launch Services file-open launch (grace-delay read of startup_opened_file); cold-start file double-click opens only that file.
2026-06-29 [note] Version bumped 2.2.3->2.2.4 (package.json source; sync-version.sh pre-run propagated to tauri.conf.json + Cargo.toml); local unsigned build (BoltPage.app + BoltPage_2.2.4_aarch64.dmg) for testing the cold-start file-open fix.
2 changes: 1 addition & 1 deletion boltpage/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions boltpage/Homebrew/Casks/boltpage.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
cask "boltpage" do
version "2.2.1"
version "2.2.3"

name "BoltPage"
desc "Fast, lightweight Markdown viewer and editor"
Expand All @@ -8,12 +8,12 @@
# Update these URLs with your GitHub releases or hosting location
on_arm do
url "https://github.com/Silverfell/BoltPage/releases/download/v#{version}/BoltPage-#{version}-arm64.dmg"
sha256 "0f78d8c98452a11e97f5ac163e207c7d3f15464b963c0bd57708df309ae0d539"
sha256 "338a913434d2f7734840b3835ba483d75083b79d87bdf1c68c6711b71695ca4e"
end

on_intel do
url "https://github.com/Silverfell/BoltPage/releases/download/v#{version}/BoltPage-#{version}-x64.dmg"
sha256 "bd149007a59e3788eae8aac8722fc583bbafef239eb109c26a32d953744edef3"
sha256 "58f71933508d64a4de01d300addebcfae9462982ed4e8a90e488c4f0ce8e777e"
end

auto_updates false
Expand Down
2 changes: 1 addition & 1 deletion boltpage/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "BoltPage",
"private": true,
"version": "2.2.3",
"version": "2.2.4",
"type": "module",
"scripts": {
"tauri": "tauri"
Expand Down
2 changes: 1 addition & 1 deletion boltpage/src-tauri/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "boltpage"
version = "2.2.3"
version = "2.2.4"
description = "A Tauri App"
authors = ["BoltPage Contributors"]
edition = "2021"
Expand Down
19 changes: 19 additions & 0 deletions boltpage/src-tauri/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,12 @@ async fn setup_cli_access() -> Result<String, String> {

// --- App entry point ---

/// Grace period after Ready to let a Launch Services file-open (RunEvent::Opened)
/// land before deciding session-restore-vs-welcome. A cold-start file double-click
/// delivers its file via Opened, which can arrive just after Ready; observing it
/// here lets a file launch open ONLY the clicked file (no session restore).
const STARTUP_OPENED_GRACE_MS: u64 = 100;

/// One-time startup window resolution, run on RunEvent::Ready (after Launch
/// Services has had its chance to deliver file-open URLs via RunEvent::Opened).
///
Expand All @@ -267,6 +273,19 @@ async fn resolve_startup_windows(app: tauri::AppHandle) {
return;
}

// A Launch Services file-open (Finder double-click) arrives via RunEvent::Opened
// with had_cli_args=false and can land just after Ready. Wait briefly so it is
// observable here; if a file launch happened, the Opened handler already opened
// the clicked file, so skip session restore and the welcome window entirely.
sleep(Duration::from_millis(STARTUP_OPENED_GRACE_MS)).await;
if app
.state::<AppState>()
.startup_opened_file
.load(Ordering::SeqCst)
{
return;
}

// Restore the previous session (preview windows open at last quit),
// oldest-opened first.
let session: Vec<std::path::PathBuf> = prefs::read_session_paths(&app)
Expand Down
2 changes: 1 addition & 1 deletion boltpage/src-tauri/tauri.conf.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"$schema": "https://schema.tauri.app/config/2",
"productName": "BoltPage",
"version": "2.2.3",
"version": "2.2.4",
"identifier": "com.dpm.boltpage",
"build": {
"frontendDist": "../src",
Expand Down
Loading