# Buttonizer Desktop — Changelog Release versions of the **published desktop build** (the DMG served at `https://buttonizer.app/download/Buttonizer.dmg`). The version bumps by `0.0.1` with every upload to the website, starting at `0.1.0`. Every release is pinned by an annotated git tag `desktop-v` whose date is the upload time. From **0.1.4** on, the app's own bundle version (`CFBundleShortVersionString`, shown in Settings) tracks the same number; the first four uploads were built before this numbering existed and reported `0.1.0` internally. The phone apps (iOS / Android) ship through their own stores and follow the store versions; where a change spans both, it is noted under the desktop entry. --- ## 0.1.6 — 2026-10-09 Build `sha256 2842549c…`, 11,368,581 bytes (md5 `1d7c1990dabb15fe11dd85b327d9d20d`), notarized and stapled. **Live resources (graphs, images) update again** - A button that rewrites a resource every second — like the CPU/Mem graph service, which writes `graph.svg` atomically (temp file + rename) — stopped refreshing. The folder-deletion fix in 0.1.5 promoted *any* rename inside a button bundle to a full list reload, so the resource counter never advanced: the icon URL kept the same `&v=` and the tile froze on screen, while the phone re-read the whole button list (151 buttons) every second. - Renames/creates/removes are a list change only when they happen **outside** the bundle — a folder, or a bundle directory itself. Events inside a bundle stay resource events. The desktop watcher also gained the same 500 ms per-path floor the phone path already had, so one atomic write publishes exactly one update. Measured on the Mac: the CPU/Mem tile went from 24 “list changed” events per 12 s (with zero resource events) to one resource event per second, and the window repaints every second again. Folder deletion still propagates immediately. ## 0.1.5 — 2026-10-06 Build `sha256 bf12d7c5…`, 11,361,048 bytes (md5 `ed57d3d1436b9092e6e6d119d494f26c`), notarized and stapled. **Logs you can actually read** - Run output, stderr, the live tail, `tail.log` and history now render ANSI colors and styles. The desktop had no ANSI handling at all, so `\033[32m` and friends showed up literally. Bold/dim/italic/underline/strike, the 16 colors, 256-color (`38;5;n`) and true color (`38;2;r;g;b`) are supported; other sequences (cursor movement, OSC) are stripped. - Guards against the black-on-black regression: color is only applied where the code asks for it (no explicit foreground inherits the theme text color), backgrounds stay transparent unless set, and ANSI black maps to a theme variable that remains readable on dark panels. **Buttons that disappear, stay gone** - Deleting a whole button folder now reaches the phone and the desktop list immediately. A `buttons/` directory event was classified as a resource-only change, so the phone kept showing the deleted tile — measured 13 s with the tile still present and zero `rpc list_buttons`. Both the phone path and the desktop UI path now promote a bundle-directory event to a list change (after the fix the phone re-reads within 5 s). **A sidebar you can get out of the way** - Collapse the sidebar and the body fills the whole window (the 26 px strip that used to remain is gone). The reveal button lives in the body header (Library / Notifications / Settings), and ⌘\ (macOS) or Ctrl+\ toggles it. The collapsed state is remembered. **Phone apps in the same period** (iOS / Android, distributed separately) - The top bar (title + toolbar) follows the scroll and hides 3 s after scrolling stops, including on first entry; screens that cannot scroll never hide it. - Landscape: the sidebar collapses and content uses the full width. - `Desktops (n/max)` counts paired desktops, not currently-online ones. - Folder view: `Close` only appears after 2 s without a connection (no more flicker), and a desktop you switched off is not connected to. **Hub (hosted service)** - Pairing windows survive a hub restart — they were memory-only, so a long-lived demo/review code died on every deploy. - Push notifications fall back between the APNs sandbox and production gateways, so a phone running a TestFlight/App Store build gets alerts even though the hub's default environment is sandbox. ## 0.1.4 — 2026-10-04 Build `sha256 7d9e7f58…`, 11,358,899 bytes (md5 `12c4c6478dd0f6108004f41992818dca`), notarized and stapled. **Faster phone channel** - Incoming messages now wake the host immediately instead of the 200 ms polling loop. Measured on the same Wi-Fi (iPhone 16 Pro ↔ Mac): phone RPC round-trip **208 ms → 6.1 ms** (raw TCP on the same path: 5.6 ms), so phone taps, lists and logs react in one frame instead of up to a fifth of a second. **Access control** - **New phone default** — a phone that has no access-control entry of its own (i.e. a newly paired phone) starts from a default you set next to `Paired phones`: the allowed folder subtree plus whether editing is allowed. Phones that already have their own setting are untouched. **Fewer, lighter updates** - The notification badge / notification view update from file events instead of a 5 s poll (measured ~70 ms). - Service status changes are pushed to phones and cost one small status query instead of re-reading the entire button list. - Background-graph resources are de-duplicated: atomic-write temp files no longer produce events, and a per-file 500 ms floor keeps a once-per-second graph at exactly one event per second. This also stops the phone from decoding a new graph image more often than it changes. **Phone apps in the same period** (iOS / Android, distributed separately) - Running a button no longer re-downloads and re-parses the full button list (149 buttons ≈ 577 KB per run); service state is confirmed with one small status query. - iOS: SVG backgrounds (e.g. the CPU/Mem graph) reuse a single WebView for rasterization instead of creating one per update — per-update cost 42–174 ms → 7 ms median, and the image cache is now bounded. --- ## 0.1.3 — 2026-09-30 (uploaded 2026-09-29 18:08 UTC) Build `sha256 035b7504…`, 11,341,425 bytes, notarized and stapled. - **Grid span buttons**: `span_cols` / `span_rows` in `button.yml` — a button can occupy two columns, two rows, or 2×2. Dragging a spanned tile can drop it anywhere, not only at the end. - **Background images** (`icon_background: true`) fill the whole tile with `cover` semantics on desktop, iOS and Android, including SVG; the covered area documented per tile shape. - **Access Control per phone** (Settings → Paired phones): a folder tree the phone may use (a checked folder includes its subfolders; `Root` is the top folder) and whether the phone may edit (create folders, edit / delete / move buttons). Enforced by the host; pushed to connected phones immediately. - **Invalid pseudo-tag**: `button.yml` syntax / semantic problems are collected and shown at the top of the editor. - **Services**: start parameters (with a dialog when a value is missing — also for services that declare defaults), a startup log collected for `service_log_seconds` (default 5 s), periodic collection for long-running services, and an unexpected-exit notification. - **`run_mode: detach`** (fire-and-forget): start it and stop tracking it — the process keeps running, and its live log is still available. - **Parameters & preview…** in the tile menu: inspect (and override) the values a run would use, without running it. - **Run history on the phone**: the channel exposes host run history, and logs are shown as one time-ordered list with per-row source badges. - Notifications: `POST /api/notify` with `device_id:"*"` broadcasts to every paired phone, and `BTZ_PAIRED_DEVICES` is exported for button scripts. - Tile text (title / status chip / icon slot) is unified to the iOS spec, and desktop tiles are 16:9 per cell like the phones. - Live background resources refresh from file-watch events (no polling). - Linux: tray icon, emoji/CJK fonts, bind-scope containment (loopback ⊂ lan ⊂ global). ## 0.1.2 — 2026-09-14 Uploaded with cache-buster `?v=e1be0104` (DMG `md5 e1be0104…`, 11,236,319 bytes). - **Parameter model v1**: `text` type, multi-file `file` params, number `min`/`max`/`step` (slider), parameter groups. - **Output artifacts**: `output_path` / `output_auto_open`; large run output is paged to the phone through a spool instead of one huge RPC. - **`history_limit`** per button (default 100) with a startup sweep. - Auto-open after a run only for `run_mode: short` (Immediate). - Duplicate button ids and unloadable bundles are surfaced instead of silently hidden. - Seat rejection (free tier) no longer destroys the pairing — the extra phone's session is dropped for that session only. - RPC file chunks capped at 128 KiB. ## 0.1.1 — 2026-09-12 First build published through the reworked download page (cache-buster introduced). - `res:` / `http(s):` image icons actually render in the library. - **Paired phones** list shows name (platform) and pairing time; the desktop keeps a GUI log file. - Relay `bye` / `unpair` routing fixed — unpairing a phone also removes the hub pairing record. - Running state shows **all** active runs (services plus one-shot long runs). - Sidebar wording unified with mobile: `Immediate` / `Long Running`. - Linux: dependency containment fix (loopback ⊂ lan ⊂ global), IPv4-only ICE with restart instead of tearing the phone session down, tray icon assets. ## 0.1.0 — 2026-09-10 First published macOS desktop build. - `/download` page + landing CTA + nginx route; Developer-ID signed and notarized DMG (`Buttonizer.dmg`). - Tray app with a local REST API and the same UI served in the browser; buttons, folders, parameters, run history and the desktop channel for paired phones.