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
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,12 @@ Claude now reports HTTP client setup failures instead of panicking a background

## Installers

- **Ceiling-1.5.20-Setup.exe** - standard installer
- **Ceiling-1.5.20-portable.exe** - portable
- **Ceiling-1.5.20-Store-Setup.exe** - Microsoft Store package (WebView2 bundled)
- **Ceiling-1.5.21-Setup.exe** - standard installer
- **Ceiling-1.5.21-portable.exe** - portable
- **Ceiling-1.5.21-Store-Setup.exe** - Microsoft Store package (WebView2 bundled)

Portable builds show alerts as banners but do not keep them in the notification center. That requires the Start Menu shortcut installed by the standard or Store build.

---

**Full Changelog**: https://github.com/tsouth89/ceiling/compare/v1.5.19...v1.5.20
**Full Changelog**: https://github.com/tsouth89/ceiling/compare/v1.5.19...v1.5.21
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

## Unreleased

## [Ceiling] 1.5.20 - 2026-08-01
## [Ceiling] 1.5.21 - 2026-08-01

Patch release for duplicate scheduled-reset notifications and reliability hardening around local state and account-scoped history.

Expand All @@ -14,6 +14,7 @@ Patch release for duplicate scheduled-reset notifications and reliability harden

### Internal
- The release smoke test now asserts that the installed Start Menu shortcut carries Ceiling's AppUserModelID. That property is what lets Windows keep a notification, and 1.5.17 shipped without it: every gate checked source, while the one step that inspects the installed build never looked at it.
- Shortcut identity validation now asks the Windows Shell for `System.AppUserModel.ID`. The custom property marshaller misread a correctly packaged shortcut as empty and blocked the unpublished 1.5.20 release.

## [Ceiling] 1.5.19 - 2026-07-29

Expand Down
4 changes: 2 additions & 2 deletions Cargo.lock

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

2 changes: 1 addition & 1 deletion apps/desktop-tauri/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "desktop-tauri",
"private": true,
"version": "1.5.20",
"version": "1.5.21",
"packageManager": "pnpm@10.18.1",
"type": "module",
"scripts": {
Expand Down
2 changes: 1 addition & 1 deletion apps/desktop-tauri/src-tauri/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "codexbar-desktop-tauri"
version = "1.5.20"
version = "1.5.21"
edition = "2024"
publish = false

Expand Down
2 changes: 1 addition & 1 deletion apps/desktop-tauri/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": "Ceiling",
"version": "1.5.20",
"version": "1.5.21",
"identifier": "io.github.tsouth89.ceiling",
"build": {
"beforeDevCommand": "pnpm run dev",
Expand Down
2 changes: 1 addition & 1 deletion rust/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "codexbar"
version = "1.5.20"
version = "1.5.21"
edition = "2024"
authors = ["Ceiling Contributors"]
description = "Local-first Windows companion for monitoring AI capacity and reset times"
Expand Down
60 changes: 14 additions & 46 deletions scripts/windows-smoke-install.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -183,52 +183,20 @@ Write-Step "Start Menu shortcut: $shortcut"
# with the installer setting no such property: every alert drew a banner and was
# then discarded. Nothing caught it, because every other gate checks source
# while this is the only step that inspects what was actually installed.
# -TypeDefinition, not -MemberDefinition: this declares types, which the
# member form cannot host.
if (-not ('Ceiling.Lnk' -as [type])) {
Add-Type -Language CSharp -TypeDefinition @'
using System;
using System.Runtime.InteropServices;
namespace Ceiling {
[ComImport, Guid("00021401-0000-0000-C000-000000000046")] internal class ShellLink {}
[ComImport, Guid("0000010b-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface IPersistFile {
void GetClassID(out Guid pClassID); [PreserveSig] int IsDirty();
void Load([MarshalAs(UnmanagedType.LPWStr)] string fileName, int mode);
void Save([MarshalAs(UnmanagedType.LPWStr)] string fileName, [MarshalAs(UnmanagedType.Bool)] bool remember);
void SaveCompleted([MarshalAs(UnmanagedType.LPWStr)] string fileName);
void GetCurFile([MarshalAs(UnmanagedType.LPWStr)] out string fileName); }
[StructLayout(LayoutKind.Sequential)] internal struct PropertyKey { public Guid fmtid; public uint pid; }
[ComImport, Guid("886d8eeb-8cf2-4446-8d02-cdba1dbdcf99"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface IPropertyStore {
void GetCount(out uint count); void GetAt(uint index, out PropertyKey key);
void GetValue(ref PropertyKey key, [In, Out] PropVariant value);
void SetValue(ref PropertyKey key, PropVariant value); void Commit(); }
[StructLayout(LayoutKind.Explicit)] internal class PropVariant : IDisposable {
private const ushort VT_EMPTY = 0;
private const ushort VT_LPWSTR = 31;
[FieldOffset(0)] ushort valueType; [FieldOffset(8)] IntPtr pointer;
public string AsString() {
return valueType == VT_LPWSTR && pointer != IntPtr.Zero ? Marshal.PtrToStringUni(pointer) : ""; }
// Free only what is actually a CoTaskMem string. The field at offset 8
// overlaps a union, so a non-string variant can leave arbitrary non-zero
// bits there, and handing those to FreeCoTaskMem corrupts the heap.
// Anything else is left alone: leaking a few bytes in a short-lived check
// is strictly better than freeing memory that was never allocated.
public void Dispose() {
if (valueType == VT_LPWSTR && pointer != IntPtr.Zero) { Marshal.FreeCoTaskMem(pointer); }
valueType = VT_EMPTY; pointer = IntPtr.Zero; } }
public static class Lnk {
public static string ReadAppUserModelId(string path) {
var key = new PropertyKey { fmtid = new Guid("9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3"), pid = 5 };
var link = new ShellLink();
((IPersistFile)link).Load(path, 0);
using (var value = new PropVariant()) {
((IPropertyStore)link).GetValue(ref key, value);
return value.AsString(); } } } }
'@
}
$shortcutAumid = [Ceiling.Lnk]::ReadAppUserModelId($shortcut)
# Ask the Windows Shell for the canonical property value. The previous custom
# PROPVARIANT marshaller assumed VT_LPWSTR, but Shell links can surface the
# value through another string variant; that made a correct installer look
# broken and blocked the 1.5.20 release after signing and packaging succeeded.
$shell = New-Object -ComObject Shell.Application
$shortcutFolder = $shell.Namespace((Split-Path -Parent $shortcut))
if (-not $shortcutFolder) {
throw "Could not open the Start Menu shortcut folder: $(Split-Path -Parent $shortcut)"
}
$shortcutItem = $shortcutFolder.ParseName((Split-Path -Leaf $shortcut))
if (-not $shortcutItem) {
throw "Could not inspect the Start Menu shortcut: $shortcut"
}
$shortcutAumid = [string]$shortcutItem.ExtendedProperty("System.AppUserModel.ID")
if ($shortcutAumid -ne $ExpectedAppUserModelId) {
throw "Start Menu shortcut publishes AppUserModelID '$shortcutAumid' but Ceiling toasts under '$ExpectedAppUserModelId'. Windows will show alerts as banners and then discard them instead of keeping them in the notification center. Check AppUserModelID on the [Icons] entries in rust/installer/codexbar.iss."
}
Expand Down
4 changes: 2 additions & 2 deletions version.env
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
MARKETING_VERSION=1.5.20
BUILD_NUMBER=122
MARKETING_VERSION=1.5.21
BUILD_NUMBER=123
Loading