Conversation
Bazaar resolves a cached AppStream icon only at <appstream dir>/icons/flatpak/<size>/<file> (bz-appstream-parser.c). An ostree remote's appstream branch links icons/flatpak/<size> to icons/<size>, but flatpak writes an OCI remote's catalogue from the image labels into icons/<size>/ only (flatpak_oci_index_make_appstream), so on the TunaOS remote every cached icon is skipped and Compass shows a blank tile. Mariner and the other TunaOS apps have the same problem. The only other source Bazaar reads is a remote icon URL, and appstreamcli compose drops any icon in the metainfo, so the URL has to be added after the build. publish-flatpak.yaml now adds <icon type="remote"> 64 and 128 entries to each image's appdata label. They point at PNGs committed under packaging/flatpak/icons/ and are pinned to the commit that was built. The workflow rewrites the config, manifest and index digests, then fetches the URLs and checks that they serve the label's PNG. flatpak.yaml checks the same thing on every build: the composed AppStream has cached 64/128 PNGs, they match the committed ones, and the OCI image made the publish way carries both the icon labels and the remote URLs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UtGVEzDmYTdpsuEQErmmLn
…t picks Calculator: Ctrl+B over the answer in root search opens upstream v0.29.0's RootCalculatorSection::actionPanel: Copy Result, Copy Question And Answer, Put answer in search bar, Open Calculator History (no "Copy unformatted answer": fend prints one form). The action audit lists and runs them, counts text put in the search bar as an effect, and fails when a kind of root row opens no panel. Over a short list the card grows to hold the whole panel instead of cutting it off. Onboarding: the link buttons say "Opened in browser" on the card, or why not (including without an engine); a step's notice clears when the step changes. The theme picker is covered by a paint test. Continue and Finish use the Adwaita suggested action, Back and the link buttons the neutral button, Install and Try Again neutral, Installing and Installed flat; the boxes are boxed lists and the dropdown Adwaita's. Recommendations: four Raycast store extensions that render in Suite 1 and need no account, key or AppleScript (Google Translate, Google Search, GIF Search, Tailwind CSS) and three Vicinae ones, each labelled with its store. An install reports through the store detail page's store_changed. Tests check Suite 1's verdict, its corpus's author for each, and that none is redirected. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UtGVEzDmYTdpsuEQErmmLn
Every text field in a form had on_submit(PreferencesSubmit), and the key handler also turns Enter into PreferencesSubmit. listen_with sees the event whether or not the field captured it, so one Enter submitted twice: shortcuts saved twice, scripts and quicklinks ran twice, and Set alias saved and then launched the selected row. The key handler is now the one path; the fields no longer submit. Simulator tests press Enter once in each form (shortcut, quicklink arguments, script arguments, extension arguments, alias, snippet) and assert exactly one submit. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UtGVEzDmYTdpsuEQErmmLn
A newly opened form (Set alias, extension and script arguments, the snippet and shortcut forms, ...) left the keyboard nowhere, so typed text was lost and Enter submitted the empty form. The form now tracks which field the keyboard is on, and the update that opens one focuses its first field, whichever path opened it. Tab and Shift+Tab move through every field, including the ones Iced cannot focus: a checkbox (Space ticks it) and a dropdown (Space and the arrows step it), each drawn with a ring while the keyboard is on it. That makes the snippet form's "Expand as word" reachable. The arguments form said "Enter: save and run"; arguments are this run's and are not saved, so it says "Enter: run". Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UtGVEzDmYTdpsuEQErmmLn
… P-10) Theme::palette now passes each palette through Palette::accessible, which moves a colour toward black or white only as far as it takes (compass_core::contrast::ensure_contrast): text, secondary text and the accent reach 4.5:1 against the card, the field and the boxed lists, and the selection's fill reaches 4.5:1 against the text on it. Palette::control is the hairline pushed to 3:1, for what marks out a control: an entry's frame, a switch's off track, the onboarding dots, a font tile's outline. Adwaita selects in #1c71d8 (white on it 4.77:1, was 3.77:1 on #3584e4), the dark accent is #78aeed and the dark secondary text #a3a29f (4.73:1 on a boxed list, was 4.24:1). The search placeholder is the secondary text colour (was Iced's faded text, 3.03:1 in light); a disabled button keeps a readable label; onboarding draws its buttons and dropdown the Adwaita way. A test checks every curated theme in both appearances and every file in extra/themes against the thresholds. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UtGVEzDmYTdpsuEQErmmLn
…ot focus adwaita::focus_ring and adwaita::ringed draw Adwaita's outline: a 2 px line in the accent, 2 px out from the control, so it shows around a switch that is itself filled with the accent. The room is kept whether or not the control has the keyboard, so nothing moves when it does. The accent is held at 4.5:1 against every background by the palette layer; the old ring was the accent at half opacity, 1.9 to 2.2:1. An entry's own ring is the full accent too. crate::focus is the walk Tab and Shift+Tab take over a page's controls in the order they are drawn, back to the search field past either end, for the pages (Settings, onboarding) whose switches, dropdowns and buttons Iced 0.14's focus_next skips. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UtGVEzDmYTdpsuEQErmmLn
Both processes watch compass.json and apply a change at once, so hand edits and `compass theme set` no longer wait for a restart. A value of the wrong type is set aside on its own (serde_path_to_error) instead of discarding the whole file, and kept as written; unknown keys and unknown theme, preset, colour scheme and keybinding names are reported with a "did you mean" in the engine log, `compass doctor` (new config.file check) and the settings view. The published schema closes its sections with additionalProperties: false. Writers edit the file in place through jsonc-parser's CST, keeping key order, indentation and comments, and CLI and engine writers no longer replace an unreadable file with defaults. The settings view puts a switch back when its write is refused and draws the error in Adwaita's error colour rather than the link colour. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UtGVEzDmYTdpsuEQErmmLn
Anything the launcher copied (the calculator's Enter, emoji, Copy name, Copy Deeplink, ...) was lost as soon as the window hid. iced::clipboard puts the source on the window's Wayland connection, and iced_layershell (remove_compositor) and iced_winit both drop it with the last surface. Copies now go to the engine (Request::CopyText, protocol v23), which sets them over data-control on wlroots and through the GNOME Shell extension elsewhere, the way pasting already did. Where the engine has no clipboard the window copies through Iced as before, which holds while the window does. Copy name, Copy path, Copy Deeplink and Copy ID now hide with the "Copied to clipboard" HUD, as CopyToClipboardAction does. The calculator copies the value, as the C++ copies answer.text (Numen keeps the unit apart): 88.0669308675, not "approx. 88.0669308675 EUR". Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UtGVEzDmYTdpsuEQErmmLn
Tab only reached the text fields: Iced's focus_next skips switches, dropdowns and buttons, so Record Shortcut, the hotkey button, every switch and every dropdown needed a mouse. The settings page now keeps its own focus over SettingsPage::controls, every control the page draws in the order it draws them, and: - Tab and Shift+Tab walk them and come back to the search field; once a control has the keyboard the arrows do too. - Space or Enter flips a switch, presses a button (the hotkey, Record Shortcut, Preferences, the About links) or opens a dropdown, whose options then show under its row, the arrows moving the highlight and Enter or Space picking it. - The page scrolls the focused control (or highlighted option) into view. - Page Up, Page Down, Home and End scroll the page; Home and End stay the field's while text is being edited. - Escape closes a dropdown, then gives the keyboard back to the search field, then leaves. - The control with the keyboard has the 2 px accent ring. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UtGVEzDmYTdpsuEQErmmLn
…, RC-14) A page opened at the scroll offset the previous one was left at, and a page picked with the arrows below the sidebar's fold stayed out of sight. Choosing a page by click, by the arrows, by a search or by a deeplink now snaps the body to its top and scrolls the sidebar to the selected row. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UtGVEzDmYTdpsuEQErmmLn
On a wlroots compositor the launcher's key is bound in the compositor's own configuration, so portal.global-shortcuts now passes there and gives the exact line (bindsym/bind/spawn, with the Flatpak command inside the Flatpak) instead of failing, and --check-only exits 0. Sway is found by SWAYSOCK, Hyprland and niri by their own variables, and the desktop check says so instead of "not a GNOME session ... Phase 5". The wlroots check no longer counts the compositor binding as a missing hotkey. New checks: clipboard.history (data control, or the Shell extension on GNOME) and keyring (Secret Service present, unlocked, with what to install and how to start it on Sway). A portal that is still starting on the first run is asked again after a short grace instead of failing. Removed internal notes from user text: Phase 5, the C++ helper/engine, PLAN.md, #118 and the --engine flag (now hidden). The engine no longer logs "window switching unavailable" without a session bus off GNOME. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UtGVEzDmYTdpsuEQErmmLn
…s well F-6: after a compact or inline script ran from its form or the panel, the search field no longer had the keyboard, so typing went nowhere, and Enter launched the hidden selected row, running the script again. The search field now gets the keyboard back when a one-line run starts, and while a message stands in place of the results Enter puts the results back rather than launching a row nobody can see. Typing replaces the line. F-7: the full-output view scrolls with the arrows, Page Up and Down, Home and End; it takes the card's width, so its scrollbar is at the edge rather than beside a narrow column; it has Copy output (Ctrl+Shift+C), which copies the text without its colour codes; and a non-zero exit reads "Failed after 0.1s (exit code 3)" in red rather than "Done". Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UtGVEzDmYTdpsuEQErmmLn
Every answer to the history query put the selection back on the first row, including the reload after a pin, a delete or a new copy. A Ctrl+X after any of those removed whatever was at the top (often a pinned entry), not the entry the person had been on. Removal was already by entry id; the selection is now kept by id across a reload of the same filter, staying at the same position when its entry is the one removed. A new filter still starts at the top. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UtGVEzDmYTdpsuEQErmmLn
The search field only scored page and provider names, so "quick launch" or "translucent" found nothing. Each setting's label and description are now scored too, with compass-search's fuzzy matching (the label counting twice the description), and a page a setting matched on is listed and ranked by the better of its name and that setting. The best page is shown, its matching rows are tinted with an accent outline, the best one is scrolled into view, and Enter in the search field takes the keyboard to it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UtGVEzDmYTdpsuEQErmmLn
`compass start --hidden` runs at login, so a due first-run flow now waits until the launcher is first shown instead of opening a window at startup. Closing the flow with Escape or the hotkey records it as seen, so it is not shown again at every login, and Finish leaves the launcher open at its search. A home carried over from Vicinae (the vicinae directory or its symlink, or Vicinae's settings.json) skips the flow. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UtGVEzDmYTdpsuEQErmmLn
The flow took Enter and Escape and nothing else, and Escape hid the launcher from any step. Each step's controls (the theme dropdown, Open Docs, each Install that can be pressed, GitHub) and then Back and Continue are now a Tab order, with Space or Enter to press the focused one and the 2 px ring on it; the theme dropdown opens from the keyboard as a list under its row that the arrows move through. Escape closes that list, else goes back a step, and closes the flow only from the first. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UtGVEzDmYTdpsuEQErmmLn
With text in the root search, Escape hid the launcher and kept the text for the next summon. Upstream Vicinae v0.29.0's NavigationController::goBack at the root search closes the window only when the search text is empty and otherwise clears it, as Raycast does; Compass now does the same. The Keybindings page says so. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UtGVEzDmYTdpsuEQErmmLn
A store listing, an extension's Markdown detail, a store's introduction and Create Extension's result page scrolled only with the wheel: the arrows moved a selection there is none of. Up and Down now scroll them by a line, Page Up and Page Down by most of the card, Home and End to either end (scroll::reading_key). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UtGVEzDmYTdpsuEQErmmLn
F-10: Search Files' and Switch Windows' key branches took every key and sat above the Ctrl+B check, so Ctrl+B never opened their panels (and with a panel open the arrows still moved the list). They now step aside for the panel's keys, and Search Files' panel is the file actions upstream v0.29.0 offers (Open, Show in file browser, Open with..., Copy file, Copy file path, ...). F-12: a panel advertised shortcuts (Copy Deeplink Ctrl+Shift+C, Copy file Ctrl+Shift+C, Run again Ctrl+R, ...) that did nothing unless the panel was open, and some not even then. A chord now runs the action that advertises it, over the open panel or over the panel Ctrl+B would open, for every panel; the keybinding scheme's movement chords keep their meaning, and a chord no action claims changes nothing. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UtGVEzDmYTdpsuEQErmmLn
Up (or the scheme's up chord) at the top of the list replaces the query with the last search, as upstream does, but what was being typed was lost and Down only moved the list. The query being typed is now kept when the walk starts, and Down steps back towards the newest search and then puts it back (root_view::newer_history_entry). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UtGVEzDmYTdpsuEQErmmLn
`compass deeplink compass://launch/commands/clipboard-history` was refused by the CLI's own pre-filter, which knew the OAuth redirect, settings and store links but not the launch links the engine's OpenDeeplink opens (parse_launch_link). It now forwards those too. The bare `compass <url>` form the help promises only worked with the URL as the very first argument; with a global option before it (`compass --socket <path> <url>`) the URL was taken for a subcommand and the CLI exited 2. The first argument that is not a global option is now the one looked at. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UtGVEzDmYTdpsuEQErmmLn
A compass.json moved from vicinae.json still holds Vicinae's keys, which
nothing read. The engine now translates them at start the way
settings.json is translated, keeping Compass's own keys and the original
as compass.json.vicinae.bak. `compass config migrate` also looks in
~/.config/vicinae before Compass has run once.
pop_to_root_on_close is carried over and implemented as
launcher.pop_to_root_on_close ("Clear the search on close" in Settings),
off by default as in Vicinae v0.29.0's default config. font and
favicon_service, which Compass reads as Vicinae writes them, are carried
over instead of being listed as left behind.
The theme note names the light theme as it was written, a chosen theme
wins over a default one whichever variant it was set for, and a default
light theme is no longer reported as dropped. The "using the migrated
settings" line is logged once per process instead of on every read.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UtGVEzDmYTdpsuEQErmmLn
expand() put argument values (and the clipboard and selection) into the
link as typed, as upstream does, so `?q={query}` with
`is:open label:bug & more` searched for `is:open label:bug ` and sent
` more` as a parameter of its own. In a URL template (a scheme and ://
before any placeholder, not file:) each value is now percent-encoded,
keeping only RFC 3986's unreserved characters and `/`. A link that is all
placeholder, a path or a command line is filled in as before. Recorded
in PARITY (Shortcuts, row 11).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UtGVEzDmYTdpsuEQErmmLn
…nd badges (F-11, m8, RC-14)
The root search's status bar held only the clock, so the action panel
was found by accident. It now carries what Enter does to the selected
row ("Open", "Open command", "Run script", ...) and "Actions Ctrl+B", the
footer dmenu already draws, with the clock kept as its title.
Shortcut badges showed the binding as stored, "enter" next to "Ctrl+C";
key_combo::badge reads every spelling the same way: Enter, Ctrl+Shift+C,
Ctrl+Shift+arrow. Action titles mixed title and sentence case, as
upstream's do; they are now all sentence case, the case most of upstream
v0.29.0's action titles use (42 of 74 multi-word ones), with acronyms and
names kept. ACTION-AUDIT.md is regenerated for the new titles.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UtGVEzDmYTdpsuEQErmmLn
- The Vicinae Store is named as the third-party store it is (command subtitle, intro, search placeholder, detail titles); the Raycast intro says what "these limitations" are; Raycast detail pages are titled "Raycast Store - ..."; About no longer says "compatible with Vicinae". - The theme template is no longer "Vicinae Dark" with a docs.vicinae.com link; getting-started gains a Themes section it points to. - Settings' "Not in Compass" rows and errors lose developer notes (Iced, COMPASS_LAYER_SHELL, "a hard fork", Qt, "the engine log says which", "the engine has no session bus"); folder fields say what separates them; Color, not Colour; sentence case for labels. - CLI help and schema descriptions lose #153, C++, Qt and ADR notes. - The power confirmation asks a question and has a whole sentence. - Hibernate's description no longer contains "restored", so it does not answer "store"; an item the search already lists is not offered again as a fallback ("docs" listed Search Files twice). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UtGVEzDmYTdpsuEQErmmLn
The ring around a dropdown the keyboard is on was a padded container, which set the dropdown in from the text fields above it. It is now the dropdown's own border, so it lines up. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UtGVEzDmYTdpsuEQErmmLn
The Super modifier is written "Super" instead of the ◈ glyph. On Sway, Hyprland and niri (found by their own socket variables) the settings view no longer offers a hotkey recorder whose key nothing would bind: the row says "Set in Sway" and gives the line for the compositor's configuration. Inside the Flatpak (/.flatpak-info) every instruction uses `flatpak run org.tunaos.compass toggle`. Onboarding's hotkey row and its last step say the same, and the last step says that Finish opens the launcher. The docs give the Flatpak bindings too. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UtGVEzDmYTdpsuEQErmmLn
… off the card With every theme file listed, the list opened from the keyboard grew the "Make it your own" step past the card's fixed height. It now scrolls past five themes, and the arrows keep the highlighted one in view. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UtGVEzDmYTdpsuEQErmmLn
With nothing typed the suggestions fill the card, and the new status bar (and the clock before it) was pushed off its foot. The list now scrolls in the room the card has left after the field and the bar. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UtGVEzDmYTdpsuEQErmmLn
`@compass.*` header keys are accepted as Compass's spelling of `@vicinae.*` (they may be used together, not with `@raycast`), so a script written for Compass no longer fails with "Invalid schema version, expected 1"; a file with no header at all says so. Rhai scripts in the same scripts directory (a folder with script.toml) are left to the Rhai tier instead of failing as script commands, and a broken script is warned about once per process instead of at every rescan. A script directly in the scripts folder is labelled "Script" rather than "scripts". `compass script template` says on stderr where to save the file. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UtGVEzDmYTdpsuEQErmmLn
… install Blocker 1: every extension view died about two seconds after its last render with "Reading the view timed out". The engine holds an ExtensionView read for up to 20 s waiting for a change, but the window asked with the 2 s REQUEST_TIMEOUT, took the silence for a failure and stopped polling, so typing, actions, push/pop, consent and OAuth went nowhere. The hold is now compass_ipc::EXTENSION_VIEW_HOLD, shared by both sides, and the client waits long_poll_deadline(hold) = hold + 5 s. An answer that comes back unchanged is a re-poll, not a redraw. The same mismatch is fixed for RunExtensionCommand (the engine waits up to LOAD_TIMEOUT = 10 s for the runtime) and ProbeShortcut (PROBE_TIMEOUT = 3 s). Rhai script views read through the same request and are fixed by the same change. COMPASS_EXTENSION_VIEW_HOLD_MS shortens the hold for tests, never lengthens it. Blocker 2: the Raycast store built /extensions/<author>/<name>, and the API files an organisation's extension under its owner (raycast/github is 200, thomaslombart/github is 404). Listings now read `owner`; detail, install, deeplinks and the marker use it, the author is still shown. IPC v23 adds StoreEntry.owner and renames the StoreExtension/StoreInstall key to owner. Installed ids (store.raycast.<name>) carry no handle, so existing installs are untouched. raycast://extensions/<owner>/<name>/<cmd> now runs the installed command, and ownerOrAuthorName is the manifest's owner when it has one. Also: - A crash carries its real reason: the generated RPC client rejects with an Error (not a bare string), the runtime reports error.message rather than an undefined `stack`, and the engine falls back to the refusal it just sent when a crash says nothing. - Store list errors show above the rows, not below a full list. - A no-view command's failure toast or crash reaches the launcher (WindowCommand::Failure): the reason in the HUD now, and the error line when the launcher is next shown. showHUD uses the launcher's HUD. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UtGVEzDmYTdpsuEQErmmLn
install-rust-engine.sh writes the installed binary's absolute path into compass.service's ExecStart (systemd only searches its own directories for a bare name) and checks that it did. getting-started gains a "Start Compass when you log in" section: the unit needs graphical-session.target and WAYLAND_DISPLAY in the user environment, which plain Sway provides only with uwsm, sway-systemd or an import-environment line and a session target. The Privacy section now names the daily ECB exchange-rate download and how to turn it off. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UtGVEzDmYTdpsuEQErmmLn
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UtGVEzDmYTdpsuEQErmmLn
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UtGVEzDmYTdpsuEQErmmLn
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UtGVEzDmYTdpsuEQErmmLn
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UtGVEzDmYTdpsuEQErmmLn
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UtGVEzDmYTdpsuEQErmmLn
…ow are On an unnamed desktop a missing GlobalShortcuts portal warns; a portal D-Bus can start on the private bus is reported as started; on a real headless Sway the wlroots and global-shortcuts checks pass. The config CLI tests expect pop_to_root_on_close carried over and the new wording. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UtGVEzDmYTdpsuEQErmmLn
…rt a failed launcher (TIL-01) A copy in another client while the launcher was up killed the UI with "not a valid new object id ... data_offer(n)", and under `compass start` the engine with it. Root cause, from WAYLAND_DEBUG: smithay-clipboard (window_clipboard, under both iced_winit and iced_layershell, on the UI's own wl_display) releases its wl_data_device when the seat loses its keyboard, and its Drop releases it too, which both shells trigger on every hide. A data_offer the compositor had already sent then reaches the zombie device; libwayland 1.22 discards it without reserving the server-allocated id, and the next data_offer fails the id check, a fatal protocol error. Each wtype run is a keyboard coming and going, which is why the QA harness hit it. - vendor/smithay-clipboard: 0.7.3 patched to keep a device for the seat's life and one worker per display for the process (Clipboard is a handle to it). A copy made just before the launcher hides now survives the hide too. - `compass start` keeps the lease and the engine and runs the window as a hidden `launcher-child`, restarting it (hidden) when it fails, up to five times a minute; the child ends when start goes away. - The UI's errors say "could not start" only for a start failure, and "stopped unexpectedly" when the loop dies under a running launcher; an iced_winit loop that ends without the app asking (how it reports a dispatch error) is now a failure. - wlroots tests: copies racing keyboards that come and go (fails 5/5 without the patch), and a killed launcher coming back with the engine kept. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UtGVEzDmYTdpsuEQErmmLn
…ds (TIL-02) Unplugging the output the launcher was on left `toggle`, `show` and `hide` blocked forever. Root cause: layershellev's output_destroyed took the surface's unit out of its list (the unit had the output from wl_surface.enter, even with OutputOption::Active) before the Closed for it was handled, so iced_layershell could not map the close to a window and dropped it. The app waited for a Closed that never came, and the engine holds its window slot while it waits, so every later command queued behind it. - vendor/layershellev: 0.19.1 patched to ask for the close instead, which goes through the ordinary path while the unit exists and then destroys the surface. The next show opens a new surface on the current output. - `compass toggle/show/hide` give up after 10 s with a clear error rather than hang. - wlroots test: show on a second output, unplug it, then toggle/hide/show answer and the launcher process is the same one. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UtGVEzDmYTdpsuEQErmmLn
…e; toggle a launcher left behind back (TIL-04, TIL-03) TIL-04: the fixed 768x608 window did not fit 1366x768 at 150 % (911x512 logical), 1280x800 at 200 % or 1920x1080 at 200 %, and compositors centre an oversized surface, so the search field went off the top. A layer surface now opens anchored to every edge with no size, learns the room from its first configure, and is given the launcher's size fitted to it (`surface::fit`: 8 px margin, never below 360x240), drawing nothing until then. A toplevel asks for its monitor once mapped, is shrunk to fit and opens fitted after that. The list scrolls in the shorter window. TIL-03: a layer surface holding the keyboard exclusively never loses the focus, so close on focus loss never fired on Sway and a click went through to the window underneath. With the option on, a transparent backdrop layer surface now sits under the launcher and a click on it hides the launcher; its input region leaves the launcher's rectangle out, so a click on the launcher reaches it whichever surface the compositor stacks on top. On the toplevel path, `toggle` on a launcher left behind another window (option off) brings it back as a new window, which the compositor focuses, instead of hiding it; a launcher that never reported the focus (a seat with no keyboard, as in the QA harness, where Focused was never recorded) still toggles closed. Tests: fit, the backdrop region, the toggle cases, the monitor fit and the backdrop click (t0); the launcher in a window fitted to 640x400 keeps inside it and scrolls (paint tier). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UtGVEzDmYTdpsuEQErmmLn
…ancelled (P-03) Escape on "Are you sure" for a power command returned Task::none(), leaving the field without the focus; it now returns focus_search(), as the generic confirmation does. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UtGVEzDmYTdpsuEQErmmLn
List rows are a fixed height and Iced's text wraps, so a long subtitle (LibreOffice's comment, store and extension descriptions) took two lines and ran into the row below. `compass_ui::elided` shapes the line with the renderer's own paragraph at layout and draws the longest prefix that fits with an ellipsis; `list_row_parts`, which the root, store, extension and Compass settings lists all draw their rows with, uses it for the title and the subtitle. The Adwaita-style settings rows grow with their description rather than overlap, so they keep wrapping. Tests: elide's cut points (t0) and a long subtitle laid out one line tall inside its row. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UtGVEzDmYTdpsuEQErmmLn
…ll-xqa0vv # Conflicts: # crates/compass-core/src/onboarding.rs # crates/compass-ui/src/app.rs
…ll-xqa0vv # Conflicts: # crates/compass-ui/tests/paint.rs
…ll-xqa0vv # Conflicts: # crates/compass-ui/src/adwaita.rs # crates/compass-ui/src/app/onboarding.rs
…ll-xqa0vv # Conflicts: # crates/compass-ipc/src/protocol.rs # crates/compass-ui/src/app.rs # docs/rust-engine/ACTION-AUDIT.md
…ll-xqa0vv # Conflicts: # crates/compass-ui/src/app.rs # crates/compass-ui/src/app/onboarding.rs # crates/compass-ui/src/app/settings_view.rs # crates/compass-ui/src/app/settings_view/tests.rs # crates/compass-ui/src/design.rs # crates/compass/src/serve.rs # docs/rust-engine/ACTION-AUDIT.md # docs/rust-engine/PARITY.md
…rated action audit Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UtGVEzDmYTdpsuEQErmmLn
…ocused On Sway, Hyprland and niri the hotkey row is guidance, so Tab no longer lands on a recorder that is not drawn. Clearing the query with Escape handed focus back to nobody, because the text field drops it on Escape, so the next keys were lost. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UtGVEzDmYTdpsuEQErmmLn
15 tasks
…ace, closed schema The config schema now rejects unknown keys, which the reader keeps but reports, so the schema check expects them flagged. The seam check's isolated workspace copies vendor/, which [patch.crates-io] points into. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UtGVEzDmYTdpsuEQErmmLn
… on the renderer crane's buildDepsOnly stubs every Rust source, the patched crates in vendor/ among them, so clipboard_wayland built against an empty smithay_clipboard. On the runner the new window spent 8.7 s probing Vulkan before GL, past the 10 s the two new Sway tests gave their first Show. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UtGVEzDmYTdpsuEQErmmLn
Each wtype adds a keyboard and removes it, which left the seat with none. The toplevel then lost focus with no other window to take it, and toggle's behind-another-window rule reopened it instead of hiding it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UtGVEzDmYTdpsuEQErmmLn
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes from a persona QA pass over the real binary on headless Sway: newcomer, design polish, Raycast user, tiling-WM user, and keyboard-first power user. It also covers the follow-ups from #255 and the Bazaar icon. Each fix was checked against before and after screenshots of the real launcher.
Desktop integration
smithay-clipboardreleased itswl_data_devicewhen the keyboard left, and the nextdata_offerwas a protocol error. It is vendored with a patch that keeps one device per seat.compass startnow keeps the engine and restarts a failed window, up to 5 times a minute.layershellevis vendored with a patch so the close is delivered.toggle/show/hidetime out after 10 s.Clipboard and input
Request::CopyText, so the engine copies over data-control or the Shell helper. The calculator copies the bare value, as upstream does.compass deeplink …and a bare link both work.Keyboard, accessibility, discoverability
adwaita::focus_ring) shows where you are.Palette::accessible()brings every theme to WCAG AA, with a test over every theme. Examples:Config, doctor, wording
compass.jsonreloads live in both processes.compass doctor.--hiddenwaits for the first show, Escape records it as seen, and migrated Vicinae homes skip it.vicinae.jsonis translated with a backup, andpop_to_root_on_closebecomes "Clear the search on close".@compass.*headers are accepted, a missing header gets a clear error, and Rhai folders no longer cause warnings.ExecStartuses the real prefix, and the docs cover starting at login.Extensions and the follow-ups from #255
EXTENSION_VIEW_HOLDplus a margin) and re-polls on timeout.StoreEntry::owneris new in IPC v23.Flatpak / Bazaar
The OCI appdata label now carries
<icon type="remote">URLs. Bazaar reads cached icons only fromicons/flatpak/<size>/, which OCI remotes don't populate. Addsscripts/flatpak/appstream-icons.py(add-remote, check-oci, check-build) and the committed 64 and 128 px icons.Validation
cargo fmt --check,cargo clippy --workspace --all-targets -D warningsandRUSTDOCFLAGS=-D warnings cargo doc --workspace --no-deps: clean.COMPASS_REQUIRE_RUNTIME=1 cargo test --workspace --no-fail-fast: 4808 passed, 0 failed, 2 ignored, after rebuilding the extension runtime andcompass-sandbox.compass-uiwas re-run after the final two fixes.100 ft to m→ Enter →wl-pastegives30.48after the window hidesNot in this PR
compass.jsondocs link 404s. The URL is correct; the cause is tuna-os/docs'sync-org-docsbuild failing incheckSidebarsDocIds.smithay-clipboard,layershellev) should be offered upstream.🤖 Generated with Claude Code
https://claude.ai/code/session_01UtGVEzDmYTdpsuEQErmmLn
Generated by Claude Code