Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
307 commits
Select commit Hold shift + click to select a range
8e89f68
feat(tao): cross-window drags over the platform DnD on Wayland
kdroidFilter Sep 2, 2026
763e798
feat(tao): draw a floating satellite's header as a chip on Wayland
kdroidFilter Sep 2, 2026
34bca89
fix(tao): stop an AccessKit adapter lookup from aborting the process
kdroidFilter Sep 2, 2026
d8f7563
fix(tao): position a window before showing it, not after the map
kdroidFilter Sep 3, 2026
552355e
fix(tao): bring a reopened satellite back where the user left it
kdroidFilter Sep 3, 2026
361996c
fix(tao): make members and isPrimary answer what callers ask them
kdroidFilter Sep 3, 2026
b6b9b35
fix(tao): resolve the drop target under an inbound drag's entry point
kdroidFilter Sep 3, 2026
1fc303f
test(tao): 102 headful cases for the archetypes under real load
kdroidFilter Sep 3, 2026
385b245
fix(tao): stabilize headful test suite across CI runners
kdroidFilter Sep 3, 2026
3900afe
fix(tao): refuse a DnD session the compositor will not take
kdroidFilter Sep 3, 2026
18aa1ca
test(tao): a seeded monkey on the satellite workspace
kdroidFilter Sep 3, 2026
abcc014
fix(tao): key docked panels so a subtree follows its satellite
kdroidFilter Sep 3, 2026
20d2c5f
fix(tao): stop publishing GDK's placeholder as a window's frame
kdroidFilter Sep 3, 2026
2de0dde
fix(tao): a satellite must outlive the window it is anchored to
kdroidFilter Sep 3, 2026
ee7d9f2
fix(tao): anchor a satellite against a frame the WM has finished placing
kdroidFilter Sep 3, 2026
4f8a7e5
fix(tao): measure a window frame from both its borders, not just the top
kdroidFilter Sep 3, 2026
bab7cdf
test(tao): make the headful suite wait for real frames
kdroidFilter Sep 3, 2026
cba3748
fix(tao): bound the satellite placement settle to the map, and report…
kdroidFilter Sep 3, 2026
22c5b37
test(tao): say which windows covered the point a robot gesture aimed at
kdroidFilter Sep 3, 2026
dd39499
test(tao): one red robot case no longer takes the rest of the suite w…
kdroidFilter Sep 3, 2026
7d9ef2b
test(tao): wait for geometry that is measured, not merely published
kdroidFilter Sep 3, 2026
349e7a4
test(tao): report the geometry behind every spot the click case aims at
kdroidFilter Sep 3, 2026
17ac39d
fix(tao): never anchor a satellite to a frame position nobody published
kdroidFilter Sep 4, 2026
972428c
test(tao): the top edge of a tab starts below the resize band
kdroidFilter Sep 4, 2026
7b9ac61
test(tao): only let go of a mouse button that was pressed
kdroidFilter Sep 4, 2026
7ecac96
fix(tao): keep every window painting, and satellites alive and anchored
kdroidFilter Sep 4, 2026
4616c97
fix(tao): serve Windows redraws at the end of the batch, not inside it
kdroidFilter Sep 4, 2026
63d6e7e
test(tao): stop the frame ticker from eating the window's height
kdroidFilter Sep 4, 2026
cf6b385
test(tao): park the second dock host clear of the zones a drag aims at
kdroidFilter Sep 4, 2026
ccc6f80
chore: drop a stray local test log
kdroidFilter Sep 4, 2026
1b86ec9
Merge pull request #635 from NucleusFramework/feat/tao-satellite-window
kdroidFilter Sep 4, 2026
efcca69
feat(plugin): add nucleusOptimization startup pack
kdroidFilter Aug 31, 2026
5b0cba1
feat(application): idle GC when nucleusOptimization is on
kdroidFilter Aug 31, 2026
0404556
feat(plugin): per-knob nucleusOptimization DSL
kdroidFilter Aug 31, 2026
936e293
feat(plugin): lastJdk auto-downloads current OpenJDK for packaging
kdroidFilter Aug 31, 2026
5ccfec7
fix(tao): never hold key-event locks across PeekMessageW on Windows (…
kdroidFilter Sep 4, 2026
34847dd
fix(tao): release Windows input locks before pumping calls (#644)
kdroidFilter Sep 4, 2026
d9db738
Merge pull request #646 from NucleusFramework/port/2.6-windows-reentr…
kdroidFilter Sep 4, 2026
2dd9e49
fix(tao): converge a v2 bounds request after a placement toggle storm
kdroidFilter Sep 4, 2026
5c78ddf
Merge pull request #647 from NucleusFramework/fix/tao-v2-placement-to…
kdroidFilter Sep 4, 2026
30b9c8a
feat(tao): reclaim the GPU resource cache on the macOS Metal host
kdroidFilter Sep 4, 2026
888ab6c
fix(tao): drop the macOS resize settle purge, keep the in-drag one
kdroidFilter Sep 4, 2026
4d0419c
fix(application): keep window content on the UI applier (#636)
kdroidFilter Sep 4, 2026
8ed383e
Merge pull request #649 from NucleusFramework/port/2.6-636-composable…
kdroidFilter Sep 5, 2026
39a70ae
fix(tao): place native popup layers against the screen, not the windo…
kdroidFilter Sep 5, 2026
4c0c014
fix(tao): make native popup layer dialogs look like in-scene ones (#569)
kdroidFilter Sep 5, 2026
38e2cf6
test(tao): film the dialog's disappearance too, under a heavier scene
kdroidFilter Sep 5, 2026
62b5fac
fix(tao): keep a native dialog's surface where the dialog was while i…
kdroidFilter Sep 5, 2026
6174813
feat(tao): host the Compose context menu flyout in a native popup sur…
kdroidFilter Sep 5, 2026
817f5e8
fix(tao): make the Linux context menu behave like the OS menus it imi…
kdroidFilter Sep 5, 2026
72d7837
fix(app): give the Linux context menu the shadow its OS menus have
kdroidFilter Sep 6, 2026
8af9bb4
fix(app): cast the Windows context menu shadow WinUI casts, not the w…
kdroidFilter Sep 6, 2026
42823cd
fix(app): lay the Fluent context menu out as WinUI lays out a MenuFlyout
kdroidFilter Sep 6, 2026
22d6c02
fix(tao): make the popup draw margin behave like the transparent bord…
kdroidFilter Sep 6, 2026
940d85a
Merge pull request #651 from NucleusFramework/fix/569-native-popup-sc…
kdroidFilter Sep 6, 2026
e12225c
fix(tao): give the GraalVM test image the classes it was compiled aga…
kdroidFilter Sep 6, 2026
1589b3c
Merge pull request #657 from NucleusFramework/fix/graalvm-native-test…
kdroidFilter Sep 6, 2026
4d432e5
feat(tao): reclaim the GPU resource cache on the Linux GL host
kdroidFilter Sep 6, 2026
c774856
Merge pull request #641 from NucleusFramework/feat/638-tao-macos-gpu-…
kdroidFilter Sep 6, 2026
4aaff84
fix(tao): capture headful screenshots off the Tao thread (#658)
kdroidFilter Sep 6, 2026
410612a
Merge remote-tracking branch 'origin/main' into nucleus-2.6
kdroidFilter Sep 6, 2026
342b080
feat(tao): NativeView and TextureView headful monkeys, and the embed …
kdroidFilter Sep 6, 2026
51857bc
fix(tao): keep a Linux embed on its slot through a Wayland resize, an…
kdroidFilter Sep 6, 2026
5cd0553
fix(tao): make the Windows embed give the pointer and the keyboard back
kdroidFilter Sep 6, 2026
80d0563
fix(tao): stop a macOS embed from stalling the loop, and keep IOSurfa…
kdroidFilter Sep 7, 2026
89c8cde
fix(tao): keep a Windows window painting and its focus honest around …
kdroidFilter Sep 7, 2026
a43f910
Merge pull request #659 from NucleusFramework/feat/tao-native-view-mo…
kdroidFilter Sep 7, 2026
fe7b213
fix(tao): match AWT trackpad scrolling on macOS and surface Pan event…
kdroidFilter Sep 7, 2026
8732c0d
Merge pull request #661 from NucleusFramework/port/2.6-656-macos-trac…
kdroidFilter Sep 7, 2026
e26dd6f
feat(tao): layered dock sides, per-panel sizes and app-owned dock chrome
kdroidFilter Sep 7, 2026
d74a96a
feat(tao): stable dock ranks, and reorder a side's panels by dragging…
kdroidFilter Sep 7, 2026
254572d
feat(tao): let a satellite name the sides it may be docked on
kdroidFilter Sep 7, 2026
4c7df02
feat(tao): a fixed panel — declared docked, never torn out
kdroidFilter Sep 7, 2026
3276222
feat(tao): pin a panel to its rank, and stop offering a drag that lea…
kdroidFilter Sep 7, 2026
be9662f
feat(tao): let an app tell "move the window" from "move the satellite"
kdroidFilter Sep 7, 2026
1b6de9e
feat(examples): the reader's seforim are tabs, and its dock belongs t…
kdroidFilter Sep 7, 2026
66c9504
feat(tao): a tab strip that reorders in hand, and a drag that survive…
kdroidFilter Sep 7, 2026
d51980f
feat(tao): one drop preview everywhere — the card, drawn on the space…
kdroidFilter Sep 7, 2026
b37c9a3
feat(tao): carry a torn-out tab by its top edge, so the ghost never h…
kdroidFilter Sep 7, 2026
2aeccdf
Revert "feat(tao): carry a torn-out tab by its top edge, so the ghost…
kdroidFilter Sep 7, 2026
4baceaa
feat(tao): preview a tab drop as soon as the card reaches the strip, …
kdroidFilter Sep 7, 2026
fbb9fdf
feat(tao): a hover card for the tab under the pointer, and a click a …
kdroidFilter Sep 8, 2026
ac60857
feat(plugin): pin lastJdk to OpenJDK 27 GA with Liberica on Intel Macs
kdroidFilter Sep 16, 2026
f3e4ac6
Merge pull request #639 from NucleusFramework/feat/nucleus-optimization
kdroidFilter Sep 16, 2026
202a95e
fix(plugin): lastJdk falls back to Liberica on Windows ARM
kdroidFilter Sep 16, 2026
6a42414
Merge pull request #669 from NucleusFramework/fix/lastjdk-windows-arm…
kdroidFilter Sep 16, 2026
4790352
feat(tao): mark the satellite and dock APIs as experimental
kdroidFilter Sep 17, 2026
a6afc0c
feat(tao): mark the Chrome-like tab APIs as experimental
kdroidFilter Sep 17, 2026
e548f59
Merge pull request #663 from NucleusFramework/feat/2.6-dock-layered-s…
kdroidFilter Sep 17, 2026
4b33ed5
Merge origin/main into nucleus-2.6
kdroidFilter Sep 17, 2026
ead8cad
Merge branch 'nucleus-2.6' into feat/macos-app-extensions
kdroidFilter Sep 17, 2026
05d5a0f
fix(packaging): keep +x on embedded .appex, document network-extensio…
kdroidFilter Sep 17, 2026
1b208dd
Merge pull request #396 from NucleusFramework/feat/macos-app-extensions
kdroidFilter Sep 17, 2026
7ead403
Merge origin/main into nucleus-2.6
kdroidFilter Sep 17, 2026
0d8ed01
fix(tao): centre wrap-content windows and dialogs once measured (#546)
kdroidFilter Sep 17, 2026
4580b5c
Merge pull request #674 from NucleusFramework/fix/546-wrap-content-al…
kdroidFilter Sep 17, 2026
ef0ced9
fix(tao): fill the scene once a wrap-content window is measured (#546)
kdroidFilter Sep 17, 2026
1644564
Merge pull request #675 from NucleusFramework/fix/546-wrap-content-ti…
kdroidFilter Sep 17, 2026
455a7c6
feat(application): add exitProcessOnExit to nucleusApplication (#667)
kdroidFilter Sep 17, 2026
1efdcbe
Merge pull request #676 from NucleusFramework/feat/667-exit-process-o…
kdroidFilter Sep 17, 2026
822c6b7
Merge origin/main into nucleus-2.6
kdroidFilter Sep 17, 2026
8801e03
fix(jni): report pending JNI exceptions before clearing them (#486)
kdroidFilter Sep 17, 2026
260d464
test(tao): register TaoApplicationExitTest as JVM-only
kdroidFilter Sep 17, 2026
40c2e8d
Merge pull request #677 from NucleusFramework/fix/486-jni-exception-l…
kdroidFilter Sep 17, 2026
b92531f
fix(tao): present each resize in its own turn on macOS (#576)
kdroidFilter Sep 17, 2026
ee3f015
fix(tao): present each programmatic resize unpaced on Windows (#576)
kdroidFilter Sep 17, 2026
2fda069
fix(tao): stop wake-served redraws from starving mouse input on Windows
kdroidFilter Sep 17, 2026
32508aa
feat(window): minimizable flag to drop the minimize button (#504)
kdroidFilter Sep 17, 2026
83c1f8b
Merge pull request #680 from NucleusFramework/feat/504-minimizable
kdroidFilter Sep 17, 2026
951c35a
Merge pull request #678 from NucleusFramework/fix/576-macos-resize-pr…
kdroidFilter Sep 17, 2026
48e4c7a
fix(plugin): stop electron-builder notarizing the App Store PKG (#650)
kdroidFilter Sep 17, 2026
3164218
Merge pull request #681 from NucleusFramework/fix/650-pkg-no-notarize
kdroidFilter Sep 17, 2026
7279b62
fix(jlink): drop jdk.jlink from includeAllModules runtime images (#673)
kdroidFilter Sep 17, 2026
dae095c
Merge pull request #682 from NucleusFramework/fix/673-drop-jdk-jlink
kdroidFilter Sep 17, 2026
a4bcb69
fix(fs-watcher): shared native watcher, macOS renames (#570, #571)
kdroidFilter Sep 17, 2026
c3c3699
fix(fs-watcher): hand the canonical root to inotify as well
kdroidFilter Sep 17, 2026
948f22e
Merge pull request #683 from NucleusFramework/fix/570-571-fswatcher-s…
kdroidFilter Sep 17, 2026
e8c2034
feat(window): maximizable flag, off by default for satellite windows
kdroidFilter Sep 17, 2026
0d56452
test(application): thread maximizable through the recording window hosts
kdroidFilter Sep 17, 2026
ac3b0d8
Merge pull request #684 from NucleusFramework/feat/window-maximizable
kdroidFilter Sep 18, 2026
23dd930
Merge origin/main into nucleus-2.6
kdroidFilter Sep 18, 2026
14f8fd0
feat(core-runtime): configurable native library cache directory (#303)
kdroidFilter Sep 18, 2026
617dc63
Merge pull request #686 from NucleusFramework/feat/native-cache-dir
kdroidFilter Sep 18, 2026
5e0dd35
fix: marshal native callbacks to the host UI thread, not the AWT EDT
kdroidFilter Sep 18, 2026
6c77844
feat(pkg): Developer ID PKG with install scripts (#249)
kdroidFilter Sep 18, 2026
0972034
build: derive apiValidation exclusions from the project tree
kdroidFilter Sep 18, 2026
e9fd7d5
Merge pull request #688 from NucleusFramework/feat/249-developer-id-pkg
kdroidFilter Sep 18, 2026
e9c384c
style: fix the two outstanding ktlint violations
kdroidFilter Sep 18, 2026
7281be0
fix(notification-common): marshal macOS notification callbacks to the…
kdroidFilter Sep 18, 2026
a34eb67
fix(tao/linux): paint at the drawable's real size, not a predicted on…
kdroidFilter Sep 18, 2026
20b7a0f
Merge pull request #687 from NucleusFramework/fix/ui-thread-marshal
kdroidFilter Sep 18, 2026
fddc7ee
fix(tao/linux): pin when the pending resize lands in the buffer (#444)
kdroidFilter Sep 18, 2026
f8c86b7
test(444): dump the frames whose drawable was reallocated mid-frame
kdroidFilter Sep 18, 2026
b5cde6d
review(444): correct two comments that generalised a local observation
kdroidFilter Sep 18, 2026
f23476f
Merge pull request #689 from NucleusFramework/fix/444-wayland-drawabl…
kdroidFilter Sep 18, 2026
b21ceaf
fix(tao/macos): keep the input-source indicator off a caret that is gone
kdroidFilter Sep 19, 2026
38bd8b7
test(tao/macos): lock the caret rect's lifetime in the headful suite
kdroidFilter Sep 19, 2026
7a248b9
Merge pull request #690 from NucleusFramework/fix/macos-input-source-…
kdroidFilter Sep 19, 2026
2c7ea41
fix(tao/macos): keep hover alive through AppKit's phantom mouseExited
kdroidFilter Sep 19, 2026
b9e8b1c
test(tao): fix the three #569 popup cases red on the macOS runner
kdroidFilter Sep 19, 2026
5f9dd26
test(tao): land a robot press on its target, not where the pointer was
kdroidFilter Sep 19, 2026
3654fd0
fix(tao/linux): commit the resize frame with GTK's geometry, not afte…
kdroidFilter Sep 19, 2026
a1a19f9
fix(tao/macos): give the parent the release of the press a popup forw…
kdroidFilter Sep 19, 2026
e315620
test(tao): film the dialog animation, not the compositor's timing
kdroidFilter Sep 19, 2026
594a0bb
Merge pull request #691 from NucleusFramework/fix/444-wayland-resize-…
kdroidFilter Sep 19, 2026
2685723
fix(tao/linux): keep the toplevel's frame callbacks flowing when maxi…
kdroidFilter Sep 19, 2026
0136488
ci: publish unverified dev builds from a `-dev-` tag
kdroidFilter Sep 20, 2026
c9e258c
Merge branch 'main' into nucleus-2.6
kdroidFilter Sep 22, 2026
9c8fff6
fix(tao/macos): step AppKit's own frame animations too (#576)
kdroidFilter Sep 22, 2026
dd6fc45
Merge pull request #693 from NucleusFramework/fix/tao-macos-edge-zoom…
kdroidFilter Sep 22, 2026
184bfe0
feat(plugin): strip JRE fonts from the runtime image by default
kdroidFilter Sep 22, 2026
a84a0fc
Merge pull request #694 from NucleusFramework/feat/strip-jre-fonts
kdroidFilter Sep 22, 2026
174d45b
feat(tao): customizable tab previews, pane extent limits, RTL drop fixes
kdroidFilter Sep 22, 2026
43c081f
Merge pull request #695 from NucleusFramework/feat/tab-preview-custom…
kdroidFilter Sep 22, 2026
d2f89d3
chore(plugin): default GraalVM innovation channel to 25i4 (GraalVM 25…
kdroidFilter Sep 22, 2026
7d2b849
Merge pull request #698 from NucleusFramework/chore/graalvm-25i4
kdroidFilter Sep 22, 2026
ff38b93
fix(tao): add cancellable system quit handling
anthonyhfm Sep 22, 2026
a4801d8
fix(tao): match Electron's macOS quit semantics
kdroidFilter Sep 23, 2026
e12ad9e
Merge pull request #696 from anthonyhfm/main
kdroidFilter Sep 23, 2026
06ddbd7
test(tao): align DockLandingRectTest with the #695 split-side preview
kdroidFilter Sep 23, 2026
144bffc
Merge pull request #700 from NucleusFramework/fix/dock-landing-rect-test
kdroidFilter Sep 23, 2026
395465c
Merge branch 'main' into nucleus-2.6
kdroidFilter Sep 23, 2026
0c7f064
ci: run every Linux job on ubuntu-22.04
kdroidFilter Sep 23, 2026
7871455
Merge pull request #702 from NucleusFramework/ci/ubuntu-22.04-everywh…
kdroidFilter Sep 23, 2026
32081b0
Merge branch 'main' into nucleus-2.6
kdroidFilter Sep 23, 2026
dffd786
test(application): skip the live theme e2e without an XDG portal
kdroidFilter Sep 23, 2026
d61f892
fix(tao/linux): resolve the toplevel draw callback on its interface (…
kdroidFilter Sep 23, 2026
0ea29b0
Merge pull request #704 from NucleusFramework/fix/tao-linux-toplevel-…
kdroidFilter Sep 23, 2026
7aa9ed7
Merge pull request #703 from NucleusFramework/fix/theme-e2e-requires-…
kdroidFilter Sep 23, 2026
5d3936e
perf(tao): stop re-running layout callbacks on unrelated placements (…
kdroidFilter Sep 23, 2026
c097413
feat(tao): consume ANGLE as a Maven dependency, built for D3D11 only
kdroidFilter Sep 23, 2026
dae3bf3
ci: track dependencies with Dependabot
kdroidFilter Sep 23, 2026
fae2b60
Merge pull request #707 from NucleusFramework/feat/angle-prebuilt-nat…
kdroidFilter Sep 23, 2026
71b304d
Merge pull request #705 from NucleusFramework/perf/tao-on-layout-rect…
kdroidFilter Sep 23, 2026
5c27575
build: stop native tasks from rebuilding every run
kdroidFilter Sep 23, 2026
76f8f78
build: update to Gradle 9.8.0-rc-3
kdroidFilter Sep 23, 2026
1261873
build: let the build use up to 80% of the machine's RAM
kdroidFilter Sep 23, 2026
b886db0
fix(graalvm): allow --gc=G1 on Windows and macOS from GraalVM 25.4
kdroidFilter Sep 23, 2026
dfe9fbf
Merge pull request #708 from NucleusFramework/fix/graalvm-g1-windows-…
kdroidFilter Sep 23, 2026
f354e4e
feat(plugin): provision Node.js instead of requiring it, bump electro…
kdroidFilter Sep 23, 2026
9c667dd
ci(universal-macos): run the pinned electron-builder on a provisioned…
kdroidFilter Sep 23, 2026
139f265
feat(tao): report a stalled event loop instead of freezing silently (…
kdroidFilter Sep 24, 2026
d2166c8
style: ktlint-format three build scripts that fail preMerge on nucleu…
kdroidFilter Sep 24, 2026
c437f0c
perf(tao): park the watchdog while no window is registered
kdroidFilter Sep 24, 2026
7b2cd33
Merge pull request #709 from NucleusFramework/feat/node-auto-download
kdroidFilter Sep 24, 2026
662f4dc
fix(plugin): serialize toolchain provisioning across parallel tasks
kdroidFilter Sep 24, 2026
1d7b4df
feat(tao): let an app declare an expected stall to the watchdog
kdroidFilter Sep 24, 2026
da7fe54
perf(tao): keep the watchdog's debugger check off the startup path
kdroidFilter Sep 24, 2026
b3b926d
fix(tao): harden the watchdog against the review's findings
kdroidFilter Sep 24, 2026
70b9469
fix(tao): keep the watchdog alive under blocking listeners, GC and re…
kdroidFilter Sep 24, 2026
b363579
fix(tao): make the watchdog survive its own reporting path
kdroidFilter Sep 24, 2026
f9d9531
fix(tao): make the watchdog's restart and teardown race-free
kdroidFilter Sep 24, 2026
56e215f
Merge pull request #711 from NucleusFramework/fix/toolchain-install-lock
kdroidFilter Sep 24, 2026
2fc98e3
test(tao): concurrency monkey for the watchdog, and the bug it found
kdroidFilter Sep 24, 2026
e88db99
fix(tao): two watchdog leaks the concurrency monkey found
kdroidFilter Sep 24, 2026
b828d66
test(tao): watchdog monkey against a real window
kdroidFilter Sep 24, 2026
2713589
test(tao): watchdog monkey against an animating app, and a flake it e…
kdroidFilter Sep 24, 2026
8c145e8
feat(plugin): ship Nucleus JNI libraries next to the app instead of i…
kdroidFilter Sep 24, 2026
6cf29e4
test(tao): diagnose a frame stall, and stop demanding instant thread …
kdroidFilter Sep 24, 2026
59142ae
fix(tao): re-issue a redraw the OS never answered, instead of latchin…
kdroidFilter Sep 24, 2026
75b66eb
fix(plugin): only move the Nucleus modules' own JNI libraries out of …
kdroidFilter Sep 24, 2026
b6f1211
test(tao): tell a late recovery apart from a lost one
kdroidFilter Sep 24, 2026
6f3120a
fix(tao): never park the watchdog on an open episode
kdroidFilter Sep 24, 2026
96861c6
fix(tao): guard every log on the watchdog's own paths, not just the r…
kdroidFilter Sep 24, 2026
d3b21af
style(tao): wrap the smoke task's forwarded-property list the way ktl…
kdroidFilter Sep 24, 2026
63b7b51
style(tao): forward each smoke property by name, no multiline expression
kdroidFilter Sep 24, 2026
d61e025
Merge pull request #710 from NucleusFramework/feat/event-loop-watchdo…
kdroidFilter Sep 24, 2026
14ff2ab
fix(tao): dispatch recognized trackpad pinch as Compose Scale events …
kdroidFilter Sep 7, 2026
fa4ea46
test(tao): register the #660 scale tests and cover Ctrl+wheel headful
kdroidFilter Sep 23, 2026
cfe2020
fix(tao/macos): keep pinch and rotate from overlapping; e2e the AppKi…
kdroidFilter Sep 24, 2026
67ff413
fix(tao/macos): synthetic rotation contacts never coexist with a mous…
kdroidFilter Sep 24, 2026
45c6ecd
fix(window/macos): the trackpad rotation's contacts never start a win…
kdroidFilter Sep 24, 2026
0fee010
test(tao): the night gesture monkey tells a person at the machine fro…
kdroidFilter Sep 24, 2026
53637d8
test(tao): the title-bar rotation case measures the rotation only (#660)
kdroidFilter Sep 24, 2026
1efc875
fix(tao/linux): GDK pinch and rotation never overlap; e2e the GDK ges…
kdroidFilter Sep 24, 2026
8ac3fee
fix(tao): flush the display connections after the Linux event loop re…
kdroidFilter Sep 24, 2026
c142d20
Merge pull request #714 from NucleusFramework/fix/exit-process-on-exi…
kdroidFilter Sep 24, 2026
7dffa6d
Merge pull request #712 from NucleusFramework/feat/bundle-nucleus-nat…
kdroidFilter Sep 24, 2026
71c9604
Merge pull request #662 from NucleusFramework/fix/660-tao-trackpad-sc…
kdroidFilter Sep 24, 2026
c62f33e
ci(publish-plugin): set up JDK 21 before Gradle
kdroidFilter Sep 24, 2026
572b6d4
fix(optimization): enable idle GC in GraalVM native images
kdroidFilter Sep 24, 2026
cf4029d
Merge pull request #715 from NucleusFramework/fix/native-image-idle-gc
kdroidFilter Sep 24, 2026
73a36a7
fix(application): disable Compose system theme polling
kdroidFilter Sep 24, 2026
dda6bae
Merge pull request #716 from NucleusFramework/fix/disable-compose-the…
kdroidFilter Sep 24, 2026
a925930
fix(application): disable single instance by default in dev runs
kdroidFilter Sep 24, 2026
098b8f7
Merge pull request #717 from NucleusFramework/fix/dev-single-instance…
kdroidFilter Sep 24, 2026
810674c
feat(application): auto-initialize FileKit with the app id
kdroidFilter Sep 25, 2026
8520410
fix(plugin): refresh package.json and delete read-only app images
kdroidFilter Sep 25, 2026
d7347aa
fix(plugin): remove the appId data dir on NSIS uninstall
kdroidFilter Sep 25, 2026
68c4b77
feat(application): let apps opt out of FileKit auto-initialization
kdroidFilter Sep 25, 2026
0af4712
Merge pull request #718 from NucleusFramework/feat/filekit-auto-init
kdroidFilter Sep 25, 2026
f344491
feat(updater): hot update for Windows NSIS installs
kdroidFilter Sep 25, 2026
79c7644
fix(global-hotkey): deliver hotkey callbacks on the host UI thread
kdroidFilter Sep 25, 2026
70b4119
Merge pull request #721 from NucleusFramework/fix/global-hotkey-ui-th…
kdroidFilter Sep 25, 2026
6aee0db
feat(application): parent FileKit dialogs to a Nucleus window
kdroidFilter Sep 25, 2026
0b3c3a4
build: bump FileKit to 0.16.0
kdroidFilter Sep 25, 2026
730739e
Merge remote-tracking branch 'origin/nucleus-2.6' into feat/windows-h…
kdroidFilter Sep 25, 2026
d8c3e1a
docs(application): explain why macOS FileKit dialogs stay unparented
kdroidFilter Sep 25, 2026
332543e
Merge pull request #722 from NucleusFramework/feat/filekit-dialog-parent
kdroidFilter Sep 25, 2026
0c5c92d
Merge pull request #720 from NucleusFramework/feat/windows-hot-update
kdroidFilter Sep 25, 2026
e8053ea
build: bump dependencies
kdroidFilter Sep 25, 2026
4a44140
Merge pull request #723 from NucleusFramework/chore/bump-dependencies
kdroidFilter Sep 25, 2026
aa11325
test(plugin): match fpm script paths as YAML-escaped on Windows
kdroidFilter Sep 25, 2026
6924d50
feat(updater): test updates without publishing a release
kdroidFilter Sep 25, 2026
c784a88
feat(tao): forward back/forward mouse buttons to Compose
skyecodes Sep 25, 2026
766af43
fix(plugin): keep the Gradle classpath order in packaged launchers
kdroidFilter Sep 25, 2026
ed00a44
fix(examples): package the JDK 25 demos with a JDK 25 runtime
kdroidFilter Sep 25, 2026
899a883
Merge pull request #728 from skyecodes/feature/navigation_mouse_buttons
kdroidFilter Sep 25, 2026
567b518
Merge pull request #729 from NucleusFramework/fix/packaged-classpath-…
kdroidFilter Sep 25, 2026
1e67978
Merge pull request #725 from NucleusFramework/feat/updater-dev-testing
kdroidFilter Sep 25, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
64 changes: 64 additions & 0 deletions .claude/skills/tag-dev/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
---
name: tag-dev
description: Create and push a timestamped dev tag for the Nucleus 2.6 branch in the format v2.6.0-dev-YYYYMMDDHHMM, publishing runtime modules to Maven Central and the plugin to the Gradle Plugin Portal without running preMerge. Use when the user asks to "publish a dev build", "cut a dev", "tag dev", "publier une version dev", or similar on this project.
---

# Tag dev — Nucleus 2.6

Creates a timestamped dev tag on the current HEAD and pushes it to `origin`. The tag publishes
**unverified** artifacts: `.github/workflows/publish-maven.yaml` and `publish-plugin.yaml` skip
`preMerge` for dev tags, and the desktop / GraalVM release workflows ignore them entirely.

## Format

`v2.6.0-dev-YYYYMMDDHHMM` — e.g. `v2.6.0-dev-202609200830` for Sep 20 2026, 08:30 UTC.

Timestamp components come from `date -u +%Y%m%d%H%M` (UTC, no separators, 12 chars).

The published Maven version is the tag without the leading `v` (`2.6.0-dev-202609200830`), which
orders below `2.6.0` for Gradle and Maven, so a dev build can never shadow the real release.

## Procedure

1. **Verify the branch is a 2.6 line branch** — `nucleus-2.6` or a feature branch cut from it.
A dev tag on `main` or on the 2.5 line would publish a `2.6.0-dev-*` version from the wrong
code; abort and say so.
2. **Verify the working tree is clean** — `git status --porcelain` empty. If dirty, ask the user
whether to commit first or abort. Never tag a dirty tree: the tag is what CI builds.
3. **Verify HEAD is pushed** — `git fetch origin` then check the commit exists on the remote
(`git branch -r --contains HEAD`). A tag on an unpushed commit makes CI check out a commit
nobody else has; push the branch first (ask before pushing).
4. **Generate the timestamp** with `date -u +%Y%m%d%H%M`.
5. **Check the tag doesn't already exist** — `git tag -l v2.6.0-dev-<ts>`. If it does, use the
next minute; Maven Central versions are immutable, a retag would publish nothing.
6. **Create an annotated tag**:
```bash
git tag -a "v2.6.0-dev-<ts>" -m "v2.6.0-dev-<ts>"
```
Annotated (not lightweight) because the published history uses annotated tags.
7. **Push the tag**:
```bash
git push origin "v2.6.0-dev-<ts>"
```
8. **Report** the tag name, the commit SHA, the resulting Maven version, and the coordinates a
consumer needs, e.g.:
```kotlin
implementation("dev.nucleusframework:nucleus.decorated-window-tao:2.6.0-dev-<ts>")
```
Mention that Central takes ~15 minutes to expose the version after the workflow goes green.

## Hard rules

- Never tag `main` or the 2.5 line with this format.
- Never overwrite or force-push a tag — the version is already on Central and cannot be replaced.
- Never add `Co-Authored-By` or AI attribution to the tag message (per the project's CLAUDE.md).
- Tag message body is just the tag name itself — matches the existing convention.
- The tag must stay `v<major>.<minor>.<patch>-dev-<id>`: `.github/actions/release-tag-info`
rejects anything else, because every publish task derives its version by stripping
`refs/tags/v` from `GITHUB_REF`.

## When NOT to use this skill

- Stable releases (`v2.6.0`) — those go through the full `preMerge` gate and cut GitHub releases.
- Alpha/beta/rc prereleases — see the `tag-alpha` skill and `.github/actions/validate-release-ref`.
- Backporting onto an old commit — this skill always tags `HEAD`.
24 changes: 24 additions & 0 deletions .github/actions/build-macos-universal/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,14 @@ inputs:
description: 'Path to runtime embedded.provisionprofile for sandboxed app runtime'
required: false
default: ''
electron-builder-toolchain-dir:
description: 'Directory holding the package.json / package-lock.json of the pinned electron-builder toolchain embedded in the Nucleus plugin'
required: false
default: 'plugin-build/plugin/src/main/resources/nucleus/electron-builder'
node-version:
description: 'Node.js line to provision (a major like 22, or a pinned x.y.z). Keep in sync with the nativeDistributions { nodejs { version } } default.'
required: false
default: '22'

outputs:
zip:
Expand Down Expand Up @@ -102,6 +110,22 @@ runs:
echo "==> No sandboxed ZIPs found (App Store PKG will use electron-builder fallback)"
fi

# Same cache entry as setup-nucleus: the provisioning script uses the
# plugin's install layout, so a Node.js downloaded by either is reused.
- name: Cache Node.js toolchain
uses: actions/cache@v4
with:
path: ~/.gradle/nucleus/nodejs
key: nodejs-toolchain-${{ runner.os }}-${{ runner.arch }}-${{ inputs.node-version }}

- name: Provision Node.js and electron-builder
shell: bash
env:
NODE_LINE: ${{ inputs.node-version }}
TOOLCHAIN_DIR: ${{ inputs.electron-builder-toolchain-dir }}
TOOL_DIR: ${{ runner.temp }}/electron-builder-tool
run: bash "${{ github.action_path }}/provision-electron-builder.sh"

- name: Build universal binary
id: build
shell: bash
Expand Down
5 changes: 3 additions & 2 deletions .github/actions/build-macos-universal/build-universal.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
set -euo pipefail

# ── Required env vars ─────────────────────────────────────────────────────
: "${ARM64_ZIP:?}" "${X64_ZIP:?}" "${OUTPUT_DIR:?}"
: "${ARM64_ZIP:?}" "${X64_ZIP:?}" "${OUTPUT_DIR:?}" "${NODE_BIN:?}" "${ELECTRON_BUILDER_CLI:?}"

# ── Optional env vars (default to empty) ──────────────────────────────────
SIGNING_IDENTITY="${SIGNING_IDENTITY:-}"
Expand Down Expand Up @@ -499,8 +499,9 @@ run_electron_builder() {
codesign --force --deep --sign - "$app_copy"
fi

# Provisioned by provision-electron-builder.sh from the plugin's lock file.
CSC_IDENTITY_AUTO_DISCOVERY=false \
npx --yes electron-builder \
"$NODE_BIN" "$ELECTRON_BUILDER_CLI" \
--prepackaged "$app_copy" \
--config "$eb_dir/electron-builder.yml" \
--config.electronVersion=33.0.0 \
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
#!/usr/bin/env bash
# Provisions the same Node.js and the same pinned electron-builder toolchain the Nucleus plugin
# uses, for the universal repack — which runs electron-builder outside the plugin.
#
# - Node.js: the newest release of $NODE_LINE from nodejs.org, verified against the release's
# SHASUMS256.txt, installed with the plugin's layout (NodeToolchainProvisioner):
# <install-base>/node-<line>-darwin-<arch>/<archive top dir>/ plus a `.nucleus-provisioned`
# marker naming that top dir. A cache restored from a plugin run is therefore reused as is.
# - electron-builder: `npm ci --ignore-scripts` against the lock file embedded in the plugin, so
# every transitive package is checked against its recorded integrity hash (no `npx --yes`).
#
# Writes NODE_BIN and ELECTRON_BUILDER_CLI to $GITHUB_ENV.
set -euo pipefail

: "${NODE_LINE:?}" "${TOOLCHAIN_DIR:?}" "${TOOL_DIR:?}"
# The plugin's default cache location (<gradle-user-home>/nucleus/nodejs).
NODE_INSTALL_BASE="${NODE_INSTALL_BASE:-$HOME/.gradle/nucleus/nodejs}"

case "$(uname -m)" in
arm64 | aarch64) arch="arm64" ;;
x86_64) arch="x64" ;;
*) echo "::error::Unsupported architecture $(uname -m)" >&2; exit 1 ;;
esac

install_dir="$NODE_INSTALL_BASE/node-$NODE_LINE-darwin-$arch"
marker="$install_dir/.nucleus-provisioned"

if [[ -f "$marker" && -x "$install_dir/$(cat "$marker")/bin/node" ]]; then
node_home="$install_dir/$(cat "$marker")"
echo "==> Reusing Node.js at $node_home"
else
dist="https://nodejs.org/dist"
# Same rule as the plugin: a pinned x.y.z as is, otherwise the newest release of that major.
if [[ "$NODE_LINE" =~ ^v?[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
version="v${NODE_LINE#v}"
else
version="$(curl -fsSL "$dist/index.json" |
jq -r --arg major "$NODE_LINE" \
'[.[] | select(.version | startswith("v" + $major + "."))]
| sort_by(.version | ltrimstr("v") | split(".") | map(tonumber)) | last | .version')"
fi
if [[ -z "$version" || "$version" == "null" ]]; then
echo "::error::No Node.js release matches '$NODE_LINE'" >&2
exit 1
fi

archive="node-$version-darwin-$arch.tar.gz"
work="$(mktemp -d)"
trap 'rm -rf "$work"' EXIT

echo "==> Downloading Node.js $version from $dist/$version/$archive"
curl -fsSL -o "$work/$archive" "$dist/$version/$archive"
curl -fsSL -o "$work/SHASUMS256.txt" "$dist/$version/SHASUMS256.txt"
(cd "$work" && grep " $archive\$" SHASUMS256.txt | shasum -a 256 -c -)

tar -xzf "$work/$archive" -C "$work"
top_dir="node-$version-darwin-$arch"
rm -rf "$install_dir"
mkdir -p "$install_dir"
mv "$work/$top_dir" "$install_dir/"
echo "$top_dir" > "$marker"
node_home="$install_dir/$top_dir"
echo "==> Node.js $version installed to $node_home"
fi

node_bin="$node_home/bin/node"
# npm's launcher resolves `node` through PATH.
export PATH="$node_home/bin:$PATH"

echo "==> Provisioning electron-builder from the plugin's lock file (npm ci --ignore-scripts)"
rm -rf "$TOOL_DIR"
mkdir -p "$TOOL_DIR"
cp "$TOOLCHAIN_DIR/package.json" "$TOOLCHAIN_DIR/package-lock.json" "$TOOL_DIR/"
(cd "$TOOL_DIR" && npm ci --ignore-scripts --no-audit --no-fund --no-progress --loglevel=error)

cli="$TOOL_DIR/node_modules/electron-builder/cli.js"
if [[ ! -f "$cli" ]]; then
echo "::error::electron-builder CLI missing at $cli after npm ci" >&2
exit 1
fi
echo "==> electron-builder $("$node_bin" "$cli" --version)"

{
echo "NODE_BIN=$node_bin"
echo "ELECTRON_BUILDER_CLI=$cli"
} >> "$GITHUB_ENV"
64 changes: 64 additions & 0 deletions .github/actions/release-tag-info/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
name: Release tag info
description: Classifies the pushed tag into a release channel and derives the version the build will publish

outputs:
version:
description: Maven version the publish tasks will derive from the tag (tag name without the leading `v`)
value: ${{ steps.classify.outputs.version }}
channel:
description: '`dev` for a `v<version>-dev-<id>` tag, `release` for anything else'
value: ${{ steps.classify.outputs.channel }}
is-dev:
description: '`true` when the tag is a dev tag (publish without running preMerge)'
value: ${{ steps.classify.outputs.is-dev }}

runs:
using: composite
steps:
- name: Classify tag
id: classify
shell: bash
run: |
set -euo pipefail

if [[ "${GITHUB_REF_TYPE:-}" != "tag" ]]; then
echo "::error::release-tag-info only runs on tag refs (got '${GITHUB_REF_TYPE:-none}')."
exit 1
fi

tag="${GITHUB_REF_NAME}"

# Every publish task derives its version with `GITHUB_REF.removePrefix("refs/tags/v")`,
# so a tag that is not `v<semver>` would publish a version literally named
# `refs/tags/<tag>`. Fail here rather than on Maven Central, where it is permanent.
if [[ ! "$tag" =~ ^v[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z]+([.-][0-9A-Za-z]+)*)?$ ]]; then
echo "::error::Tag '$tag' is not a publishable version tag (expected v<major>.<minor>.<patch>[-qualifier])."
exit 1
fi

version="${tag#v}"

# Dev channel: `v2.6.0-dev-202609200830`. Cut from any branch, published without
# preMerge — the usual Kotlin-ecosystem `-dev-` build.
if [[ "$tag" =~ ^v[0-9]+\.[0-9]+\.[0-9]+-dev([.-][0-9A-Za-z]+)*$ ]]; then
channel=dev
is_dev=true
else
channel=release
is_dev=false
fi

echo "Tag '$tag' → version '$version', channel '$channel'."
{
echo "version=$version"
echo "channel=$channel"
echo "is-dev=$is_dev"
} >> "$GITHUB_OUTPUT"

{
echo "### Publishing \`$version\` (\`$channel\` channel)"
if [[ "$is_dev" == "true" ]]; then
echo ""
echo "Dev tag: \`preMerge\` is skipped."
fi
} >> "$GITHUB_STEP_SUMMARY"
27 changes: 13 additions & 14 deletions .github/actions/setup-nucleus/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,21 +31,17 @@ inputs:
required: false
default: 'false'
graalvm-version:
description: 'GraalVM toolchain version, used only as a cache-key component. Keep in sync with the graalvm { toolchain { } } DSL (e.g. 25i3, 25).'
description: 'GraalVM toolchain version, used only as a cache-key component. Keep in sync with the graalvm { toolchain { } } DSL (e.g. 25i4, 25).'
required: false
default: '25i3'
default: '25i4'
graalvm-distribution:
description: 'GraalVM distribution, used only as a cache-key component. Keep in sync with graalvm { toolchain { distribution } } (community or oracle). Changing it must not restore a cache holding the other distribution.'
required: false
default: 'community'
setup-node:
description: 'Setup Node.js'
required: false
default: 'true'
node-version:
description: 'Node.js version'
description: 'Node.js line the Nucleus plugin provisions, used only as a cache-key component. Keep in sync with the nativeDistributions { nodejs { version } } DSL.'
required: false
default: '24'
default: '22'

outputs:
java-home:
Expand All @@ -62,8 +58,7 @@ runs:
# Temurin, matching the rest of the workflows. jpackage bundles this JDK into
# the distributed app. In GraalVM mode the native image is built entirely by
# the plugin-provisioned GraalVM, so the Gradle JDK contributes nothing to
# that output. decorated-window-jbr needs no JBR here — the JBR API comes
# from the org.jetbrains.runtime:jbr-api Maven artifact.
# that output.
- name: Set up JDK
uses: actions/setup-java@v4
with:
Expand Down Expand Up @@ -155,8 +150,12 @@ runs:
uses: gradle/actions/setup-gradle@v5

# ── Node.js ─────────────────────────────────────────────────────────
- name: Setup Node.js
if: inputs.setup-node == 'true'
uses: actions/setup-node@v6
# No actions/setup-node: the Nucleus plugin downloads the Node.js it runs
# electron-builder with and caches it under ~/.gradle/nucleus/nodejs, so CI
# packages with the same toolchain a developer machine does. Only the cache
# is CI's business.
- name: Cache Node.js toolchain
uses: actions/cache@v4
with:
node-version: ${{ inputs.node-version }}
path: ~/.gradle/nucleus/nodejs
key: nodejs-toolchain-${{ runner.os }}-${{ runner.arch }}-${{ inputs.node-version }}
31 changes: 26 additions & 5 deletions .github/actions/validate-release-ref/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,19 @@ description: Validate release tags that must be cut from a specific branch

inputs:
prerelease-branch:
description: Branch that owns 2.x prerelease tags
description: >
Branch that owns the prerelease tags. Empty (the default) derives it from the tag itself,
so the check follows the release line instead of going stale every cycle.
required: false
default: nucleus-2.0
default: ''
prerelease-branch-prefix:
description: Prefix of the derived prerelease branch name (`<prefix><major>.<minor>`)
required: false
default: nucleus-
prerelease-tag-regex:
description: Bash regex for prerelease tags that must be on prerelease-branch
description: Bash regex for prerelease tags that must be on the prerelease branch
required: false
default: '^v2\.[0-9]+\.[0-9]+-(alpha|beta|rc)([.-][0-9A-Za-z]+)*$'
default: '^v[0-9]+\.[0-9]+\.[0-9]+-(alpha|beta|rc)([.-][0-9A-Za-z]+)*$'

runs:
using: composite
Expand All @@ -33,8 +39,23 @@ runs:
exit 0
fi

# The branch that owns a prerelease tag is the one named after its release line:
# `v2.6.0-rc.1` belongs on `nucleus-2.6`. Derived rather than hard-coded, because a
# pinned branch name silently protects the *previous* line once the work moves on
# (the default was still `nucleus-2.0` while 2.6 was in development, and that branch
# no longer exists on origin — every rc would have failed to fetch).
if [[ -z "$prerelease_branch" ]]; then
line="${tag#v}"
line="${line%%-*}"
prerelease_branch="${{ inputs.prerelease-branch-prefix }}${line%.*}"
echo "Derived prerelease branch '$prerelease_branch' from tag '$tag'."
fi

echo "Validating prerelease tag '$tag' against origin/$prerelease_branch..."
git fetch --no-tags origin "+refs/heads/$prerelease_branch:refs/remotes/origin/$prerelease_branch"
if ! git fetch --no-tags origin "+refs/heads/$prerelease_branch:refs/remotes/origin/$prerelease_branch"; then
echo "::error::Prerelease branch '$prerelease_branch' does not exist on origin (derived from tag '$tag')."
exit 1
fi

if git merge-base --is-ancestor "$GITHUB_SHA" "refs/remotes/origin/$prerelease_branch"; then
echo "Tag '$tag' points to a commit contained in origin/$prerelease_branch."
Expand Down
Loading
Loading