Exiting a project with auto-sync on runs requestClose(), which queued
CloseConfirm.Sync and tore down open editors before the sync ran. Scenes,
notes, and encyclopedia entries flagged unsaved edits via shouldConfirmClose(),
but TimeLineComponent returned emptySet(), so an in-progress timeline event
edit was silently discarded with no warning.
Wire TimeLineComponent.shouldConfirmClose() to the existing isEditingAndDirty()
check and add a CloseConfirm.Timeline confirmation dialog on Android/common and
desktop, mirroring the notes/encyclopedia pattern.
Closes#588
Sync, background jobs, API/email send, and UI boundaries legitimately
catch broadly; annotate each with @Suppress and a reason, and log the
exception where it was previously swallowed.
* Rename IdRepository to IdAllocator
It is a special foundational primative
* Rename SyncDataRepository to SyncJournal
It is a special foundational primative
* Rename GlobalSettingsRepository to GlobalSettingsStore
It is a special foundational primitive
* docs: add Foundation primitives tier to the architecture doc
Document IdAllocator, SyncJournal, and GlobalSettingsStore as a fixed set of
stateful, cross-cutting primitives that the whole data layer may depend on —
acyclic leaves (GlobalSettingsStore <- SyncJournal <- IdAllocator) that named
the dependency reality instead of treating it as a no-sibling violation.
The log-consumer coroutine could write to appendBuffer after another
thread (the logging framework / shutdown) had already closed it, e.g.
during CoroutineScope cancellation, throwing IllegalStateException: closed.
Make the single consumer coroutine the sole owner of the sink: it writes,
flushes, and closes appendBuffer (the latter in a finally block so it runs
on normal channel close and on cancellation alike). close() now just closes
the message channel, which ends the consumer; flush()/close() no longer
touch the sink from foreign threads. As a bonus, queued messages are
drained before the sink closes. Applies to both desktop and android.
The log-consumer coroutine could write to appendBuffer after close()
closed it from another thread (e.g. during scope cancellation on
shutdown), throwing IllegalStateException: closed.
Guard all sink access with a lock and a closed flag, and close the
message channel on close() so the consumer terminates cleanly. Applies
to both the desktop and android FileLogger.
Show an explanatory welcome dialog before the projects-directory picker so
first-time users understand why macOS is asking them to choose a folder.
Route all user-facing strings in the sandbox first-run flow through StrRes
so they're translatable via Crowdin.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The #import/#include directives were split across two lines, which clang
rejects, breaking the compileMacosBookmarksLib task for App Store builds.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Replace ad-hoc icon scripts with a single source-of-truth manifest
(scripts/assets.yaml) and a Python generator that renders every app icon,
store-listing graphic, MSIX tile, favicon, and the Play feature graphic from
two SVG sources. Compositions (icon + "Hammer" wordmark in Kingthings
Trypewriter) are defined once as percentages of canvas and reused across the
Play feature graphic, MSIX wide/splash tiles, and the Snap featured banner.
Adds the missing snap store icon, fixes the snap desktop icon to the correct
256x256 hicolor size, and routes uploads-only assets to build/store-assets/
(gitignored).
See docs/ASSET-GENERATION.md for the manifest schema.
Pass -PmacOsAppStoreRelease=true -PbuildNumber=N to produce a sandboxed,
signed .pkg ready for TestFlight upload via Transporter / iTMSTransporter.
Apple Silicon only for v1; JBR runtime stays.
- Sandbox-friendly entitlements (network.client + user-selected files
for the app; JIT/unsigned-mem/disable-library-validation for the JVM).
- JNA libjnidispatch.jnilib is pre-extracted into desktop/resources/macos/
and located via -Djna.boot.library.path so JNA never tries to extract
to a temp dir at runtime (which would hang silently in the sandbox).
- com.apple.application-identifier / team-identifier baked into the app
signature so it matches the embedded provisioning profile.
- UrlLauncher drops the Runtime.exec("open") fallback in favor of the
Desktop API only.
- Projects-directory picker is hidden in App Store builds; the sandbox
container's ~/Documents is the only writable location for v1.
- unquarantineMacApp Gradle task strips com.apple.quarantine xattrs
before pkg packaging to avoid App Store validation errors.
- New helper: desktop/scripts/build-appstore.sh — pre-flight checks,
one-shot build, codesign + pkgutil signature verification.
Signing assets and API key live in desktop/{embedded,runtime}.provisionprofile
and desktop/secrets/ (both gitignored).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Reverts the Nucleus packaging port and its follow-ups:
- 93c7973c Trying nucleus for packaging Snap stays bespoke
- 7c14bcd5 Broaden artifact staging to handle Nucleus sandboxed pipeline paths
- d24f6183 Add homepage and debMaintainer for electron-builder
- 8831e9c5 Update release workflows for Nucleus packaging
- 4af31163 Port :desktop packaging to Nucleus framework
Compose Desktop is back as the packaging backend (jpackage targets,
custom packageMsix task, bespoke buildDistSnap/AppImage/Flatpak via
registerLinuxDistributionTasks). The Nucleus runtime libraries —
nucleus.darkmode-detector and nucleus.decorated-window-jbr — are
kept for window decoration and dark-mode detection in code, along
with the JBR jvmToolchain vendor pin and the libs.versions.toml
'nucleus' version entry that they depend on.
The Nucleus-pipeline state is preserved on branch
'nucleus-build-pipeline' for future reference.
Detect the native Linux desktop scale factor and feed it to AWT via
sun.java2d.uiScale before Swing initializes. No-op on macOS/Windows and
on JetBrains Runtime (which detects scale natively); needed for any
non-JBR JVM and for future GraalVM Native Image builds.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Wrap desktop windows in JewelDecoratedWindow + JewelTitleBar so the app
draws its own title bar (works on any JVM, no JBR needed). Adds nucleus
decorated-window-jni + decorated-window-jewel artifacts, plus the Jewel
int-ui-standalone dep for the IntUiTheme wrapper that JewelDecoratedWindow
reads its colors from. Jewel artifacts live in the IntelliJ snapshots
repo (cache-redirector path resolves to cloudfront 404, the direct
www.jetbrains.com URL works).
DecoratedWindowScope implements FrameWindowScope, so the existing
EditorMenuBar (which uses FrameWindowScope.MenuBar) keeps working — the
JMenuBar will render below the custom title bar on Windows/Linux, and on
macOS it stays in the system menu bar.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Swaps the bespoke OsThemeDetector for Nucleus's dark-mode detector.
The non-composable initial LAF install uses getPlatformDarkModeDetector(),
and the live-update path inside application{} uses the isSystemInDarkMode()
composable so theme changes recompose without a manual listener.
Drops the explicit jna / jna-platform deps that only existed to back-fill
jSystemThemeDetector's transitive graph.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
electron-builder rejects .deb builds without these three fields:
homepage, author email, and Linux maintainer. The Nucleus DSL covers
all three via top-level `homepage` and `linux.debMaintainer` (which
takes "Name <email>" together).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Replaces Compose Desktop's bespoke nativeDistributions + the hand-rolled
packageMsix, snapcraft, flatpak-builder, and appimagetool tasks with
the Nucleus plugin's unified DSL. Nucleus is a fork of compose-desktop-
application that adds first-class AppX/Portable/Snap/Flatpak/AppImage
targets, so org.jetbrains.compose can no longer be applied alongside
it (task name collisions); compose.desktop.currentOs and
compose.components.uiToolingPreview are now resolved via explicit
Maven coordinates instead.
The hand-edited msix/AppxManifest.xml, snap/snapcraft.yaml, and
flatpak/*.yaml are now generated from the DSL; the source files
remain in-tree for now and will be deleted once CI validates the
nucleus output across all targets.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Move the desktop shortcut from a focus-dependent onPreviewKeyEvent modifier
to the Window-level onKeyEvent handler (same place Escape is wired), so it
works before any composable has claimed keyboard focus.