| Age | Commit message (Collapse) | Author | Files | Lines |
|
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
Avatar, Hello <login> and the real name, re-read whenever the grid view
shows again so an edit is visible on the way back from the page. Module
gains tiled, so a module can own a page without a tile.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
|
|
Parsing userctl's output and locale -a, and the git name preview, kept
out of QML so node can test them.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
|
|
busctl and kwriteconfig6 parse a value starting with '-' as an option, so
a location like '-x' failed; '--' before the value ends option parsing
(checked against both binaries).
get ran without pipefail, so a failing busctl gave empty fields and exit
0, which the page would show as a blank form. It now reads all fields
first and, on failure, prints one error= line and exits 1.
keys listed revoked, expired or invalid primaries, keys that cannot
sign, and could label a key with a revoked uid. It now skips those.
Unsetting the signing key uses --unset-all, since git exits 5 on a
multi-valued key with --unset.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
|
|
One writer for the stores other programs read: AccountsService (and with
it the passwd GECOS LibreOffice prefills from), KDE's emaildefaults and
the global git config, where the surname goes in as an initial. busctl
is asked for JSON because its plain output escapes non-ASCII as octal.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
|
|
The island's performance icon and panel are gone: the drawer page covers
them. With only one host left, the panel drops its three-column grid for
one card per row at a larger size, since the page scrolls; temperatures
get a card of their own as tiles. The files move from island/perf to
modules/perf.
A cache card ports conky's: ~/.cache and its five largest children,
measured with du each time the page opens (28ms over 2 GiB here) rather
than read from conky's 15-minute sampler file. The largest is yellow,
red past half the total, as conky had it.
The warning dot now shows only on the drawer tile.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
The git sync was meant to include user.signingkey and the spec had
dropped it, claiming nothing reads a GPG key. git does. The page offers
the secret keys gpg holds, plus None, and writes the fingerprint.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
passwd in a terminal already does it, AccountsService's SetPassword needs
admin rights and a hash, and a change desyncs the login keyring.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
A drawer row greets the login user and opens a page that edits name,
email, avatar, language and location, written where other programs
already read them: AccountsService (and through it the passwd GECOS
LibreOffice reads), KDE's emaildefaults and the global git config, with
the surname shortened to an initial for git.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
Recorded because the inverted filter looked correct, linted clean and
returned an empty list with no error.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
The island spec put per-app volume on the drawer page, and it was never
built. Each application playing audio now gets a row with its name, what it
is playing (two browser tabs are otherwise identical rows), a click-to-mute
level and its own slider.
Streams are matched on PwNodeType.AudioOutStream. Quickshell reports isSink
true for a playback stream, so the obvious isStream && !isSink filter found
nothing while Firefox played. Their properties are empty until bound, so the
page carries a PwObjectTracker for them, which stops with the drawer.
speech-dispatcher-dummy is always present and never audible, and is hidden.
The output slider runs to 150%, the ceiling the volume keybind already uses
(wpctl -l 1.5), with a tick at 100%. Input and apps stop at 100%: a boosted
microphone only clips. The meter became an inline component shared by both,
and wheel-up never lowers a level already past its maximum.
Now playing is dropped from the page: the OSD already carries it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
The side button (BTN_SIDE, Qt.BackButton) does what Escape does: closes
the history, then leaves a page for the tiles, then closes the drawer.
Both go through one back(). The first attempt let the press fall through
to the full-surface click catcher under the panel, since nothing above
it accepts that button; it never arrived while a page was open. A
MouseArea on top with z: 1, taking only the back button, works, and
left clicks still pass through it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
The first cut was small type in one long list: 471 Slackware upgrades
pushed everything below them out of sight, and the repo tag, the
versions and the name ran together across the row. Type is 2px larger
and rows taller. A section over ten rows starts folded behind a
clickable heading with its count. The version being moved to is bright,
the one being left dim, both in Inconsolata so digits line up. Every
other row is shaded to carry the eye across, and the repo is a pill in
one colour per repo, never red, green, yellow or the accent, which mean
something elsewhere.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
The tile counts what can be installed now (Slackware and the binary
repo) and what only needs a build, and goes accent when there is
something to install. It runs updatesctl while the drawer is open and
not otherwise; a result over 30 minutes old is followed by a refresh
that runs nvchecker, never after a refresh, so a failing nvchecker
cannot loop.
The page has one section per next action: Slackware upgrades, new and
removed first, then upgrade here, awaiting build, upstream newer, app
updates, the order the work is done in. Each row names the package, the
repo it comes from and the one version jump its action covers. A source
that could not be read says so under the section it empties instead of
reading as nothing pending.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
A git hash starting with a letter (3.1-a59215d) ordered behind its base,
because any trailing alphabetic chunk counted as a pre-release; only
alpha, beta, rc, pre and dev do now. Trailing zeros (1.14 against
1.14.0) compare equal instead of reading as an upstream bump. A bad line
in the slackpkg blacklist is skipped rather than crashing the script and
leaving the drawer with nothing. An AppImage keeps its key over a
flatpak of the same name, as the spec orders them, and flatpak list has
a timeout. A Slackware upgrade compares version and build, so an arch
change alone is not a row. The spec's prose now matches the code: the
upstream comparison includes the installed version.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
The awaiting-build branch also required the build to be older than
upstream, which cannot fail there: a build newer than installed was
already taken as an upgrade, so the build is at most the installed
version, which is behind upstream whenever a row is emitted. Removing
it left every test passing, which is how it was found.
The blacklisted testing/ entry sat after the main one in the fixture, so
setdefault kept the main one and the mirror-side blacklist was never
exercised; it now comes first, and dropping the check fails the test.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
A fifo with no writer blocks cat at open() the way a hard NFS mount
blocks during a NAS outage. The repo section reports unreachable within
the timeout and the mirror sections still fill.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
|
|
Compared mirror against installed, as upgrade-all does, not against
slackpkg's local ChangeLog: `slackpkg update` replaces that without
installing anything, so a diff against it reads clean after an update
that was never applied. New and removed come from the mirror's
ChangeLog, the newest Added or Removed line deciding, so a package
added and later upgraded still counts as new. Blacklisted build tags
and directories are skipped, as slackpkg skips them.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
|
|
Each nvchecker stanza lands in one section: upgrade here when the binary
repo's PACKAGES.TXT holds a newer build than installed, awaiting build
when the recipe (the user's or SBo's) has caught up but the build has
not, upstream newer when the recipe lags, app updates for AppImages and
flatpaks. Built comes from PACKAGES.TXT rather than the .info, which is
why gamescope and kitty no longer read as installable: the repo still
held the old build. The repo is on a hard NFS mount, so it is read by a
child the timeout can kill.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
|
|
nvtable compares versions for equality, which cannot tell an installed
2.1.278 from an SBo recipe of 2.1.267 that is older than it. vercmp
orders numeric chunks as numbers and treats a trailing alphabetic chunk
as a pre-release, so a kernel suffix or git hash orders as newer than
its base and never reads as behind.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
|
|
Drafting the code found two holes in the spec. Awaiting build was
limited to the user's own recipes, so an SBo package whose recipe had
caught up but was not yet built (nessus) showed in no section; it now
covers any recipe. And "the newest ChangeLog line decides" would never
call a package new once it had been upgraded after being added; only
Added and Removed lines count now. The prefix rule for kernel suffixes
is dropped as redundant: version order already ranks a suffixed version
newer, which is never behind.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
The conky updates card copies nvtable's table, where installed-behind and
repo-behind share a row and are told apart by colour, and it measured
"shipped" as the .info version: gamescope and kitty read as ready to
install while the binary repo still held the old build. The drawer module
sorts each tracked package into one action, from PACKAGES.TXT of the
binary repo rather than the recipe: upgrade here, awaiting build, upstream
newer, app updates. Slackware is compared mirror against installed, not
against slackpkg's local ChangeLog, which `slackpkg update` replaces
without installing anything; new and removed packages come from the
mirror's ChangeLog. NFS reads go through a timed-out child because the
mount is hard.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
The tile grid sits in a Flickable capped at three rows, so the fourth row
the new modules bring scrolls inside that box instead of eating the
notification space; a thin accent bar in the margin shows only when a row
is hidden. Tiles are reordered with the everyday ones first.
Performance shows the island's PerfPanel in a Page, with a tile line of CPU
and RAM and the warning dot. Perf.detailed is now a count of live PerfPanel
instances instead of a binding in the status pill: the island and the drawer
both host the panel, and a bool with two writers would let one clear it
under the other.
Clipboard reads cliphist when its page opens: search, copy on click or
Enter, delete per row, clear all behind a 3 second confirm, image entries as
thumbnails decoded once onto tmpfs. Entries reach sh as $1, never inside a
command string. A copy closes the drawer through a new Page.dismiss signal
the drawer connects like back.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
A new registry mode, status.quiet, with a row on the status page. Both tools
will play their sounds through notify-sound, which asks statusctl and plays
nothing while quiet is on, so their popups stay and only the sound goes.
Presentation sets quiet and restores it afterwards, like dnd and nolock: a
sound during a call or a game is what quiet is for.
notify-sound ignores any argument it has no sound for, because the opencode
notifier runs its command on every event, session_started and user_message
included.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
Each of its seven tiles opened a drawer page that already existed, and it
went unused. SUPER alone will open the drawer instead. Removed with it: the
status pill's controls icon, Island.toggleControls, the island IPC target,
Controls.js and its test, and the controls list in Prefs. Prefs now holds
only the pinned IP; a controls key left in desktop.json is still kept on
write, because writes merge into the parsed document.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
The drawer keeps its look and takes over: the island's controls panel goes,
since each of its tiles opened a drawer page that already existed, and SUPER
alone opens the drawer instead. The tile grid scrolls inside a three-row box
so new tiles do not eat the notification space. New: a performance page
reusing the island's Perf service, a cliphist clipboard page replacing the
rofi list, and a quiet mode in the status registry that mutes Claude and
opencode sounds through one notify-sound script while their popups stay.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
Previews are placed at their Expose.js rects and sized to them, so each
keeps its window's shape and relative size. Title and close show on hover
only, so the scatter stays clean; icon and workspace marker always show.
The keyboard selection is gone: this is a pointer feature, and Escape is
the one key left.
The top-right corner of DP-1 opens it after a 250ms glow that grows out of
the corner, which is the warning and the way out. Input is only the corner's
2x2 pixels, since a larger input region would eat clicks on the windows
below. It re-arms only when the pointer leaves while the expose is closed,
or an Escape with the pointer still in the corner reopens it. It hides while
status.gaming is set, read straight from the file: linking shared/Status.qml
would start a second game poll and fire presentation side effects twice.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
On screen the spiral alone read as loose: separation keeps the spiral's
gaps, and the previews filled 24 to 30% of the screen. Thirty rounds now
pull every window 15% closer to the centre and push them apart again,
which fills 35 to 55% and makes each preview up to 1.5x larger. Twenty
windows lay out in about 4ms.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
layout() seeds windows on a golden-angle spiral, most recent at the centre,
pushes overlapping pairs apart along the axis that costs less screen, and
fits the result with one scale so sizes stay relative. The spec's first
seed, the windows' real positions, was prototyped and dropped: every window
on this desk fills its monitor, so they started in one pile, and pushing a
pile apart made a line that still overlapped after 300 passes and filled
8 to 15% of the screen. The spiral converged in 1 to 55 passes. Comparing
overlaps in raw pixels stacked wide windows into a column, which is why the
axis choice divides by the screen's width and height.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
The window-switcher grid becomes a Mission Control scatter: previews keep
their real shape and relative size, seeded from their real positions and
pushed apart, then fitted with one scale. A top-right hot corner on DP-1
opens it after a 250ms glow that warns before it fires, and stays inert
while gaming. shared/Status.qml is not linked into window-switcher because
a second instance would run its own game poll and react to presentation
twice; the corner reads status.gaming directly.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
What the panel shows, the dot's thresholds and their lack of
hysteresis, why the public IP is pinned, and what is sampled always
versus only while open. AGENTS.md gains two gotchas found building it:
FileView reads /proc on reload(), and a hot reload does not resize an
existing layer surface, which left the panel cut off after the height
was raised.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
- The panel loads only while open. Its models are fresh arrays every
sample, so a hidden instance rebuilt its rows every 2s for the whole
session.
- The public IP fetch never kills one already running, and waits 30
minutes from the last attempt, not the last success: a rate-limited
or offline fetch was retried every minute.
- curl -4, so an IPv6 answer cannot silently stall the VPN check.
- CPU load sums only the first eight /proc/stat fields. guest and
guest_nice are already inside user and nice, and counting them again
read high while VMs ran.
- df gets timeout -k; the VRAM scan is not restarted over itself.
- The GPU name joins the host constants in Perf.qml.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
The performance grid runs past the old 360px surface and its disks
card was cut off. The surface is click-through outside the pills, so
the extra height costs nothing. A hot reload does not resize an
existing layer surface; it takes a restart of the desktop component.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
A system monitor icon before the controls icon opens the panel in the
status pill's capsule at 600px. A dot on its corner shows the worst of
temperatures, RAM, disks and the public IP check, yellow or red, so a
problem shows without opening anything. The detailed sampling runs only
while the panel is open.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
CPU with per-core bars, RAM and temperatures down the left; GPU and
network beside it; disks under those two. Colours follow conky's bands
so the numbers read as they did there. The pin beside the public IP
stores the address shown, and the address turns red when a fresh one
differs from the pin.
Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
|
|
CPU, RAM, temperatures and disks are sampled always, so the island's
icon can warn with the panel closed; per-core load, the network rate,
VRAM and the GPU fan only while the panel is open. hwmon chips are
found by name, since their numbers move across boots. df runs under
timeout so a dead NFS server keeps the last rows rather than blocking.
The public IP keeps conky's cache file and 30 minute pace.
Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
|
|
perf.pinnedIp in desktop.json, set from the performance panel's pin
button and written only on change. The address lives in the user's
state file, never in the repo. setControls and setPinnedIp share one
write so both keep keys this version does not know.
Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
|
|
/proc/stat deltas, meminfo, df rows, the fdinfo VRAM sum, byte rates,
hwmon lookup by chip name, the pubip cache in conky's format, and the
bands that colour the panel and the icon. A reading that cannot be
made is null, and null never raises the worst band, so a missing
sensor cannot raise an alarm. Only a fresh public IP can mismatch the
pinned one; a failed fetch goes stale instead.
Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
|
|
IconImage cannot be recoloured without an effect layer, so the severity
shows as a dot on the icon's corner. A stale public IP is a dash with no
age, as the Errors section already said.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
Nine tasks: two spec corrections, Perf.js with its node test, the
pinned IP in Prefs, the Perf service, the panel, the status pill
wiring, an on-screen check against the still-running conky widgets,
docs, and last the removal of those widgets from conky-theme-udt. The
plan's Perf.js was run against its test while planning.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
Sub-project 4. An icon in the status pill opens a card grid of CPU,
RAM, temperatures, GPU, disks and network, read from the same /proc,
/sys and hwmon sources conky uses. The icon warns on temperatures,
RAM, disks and a public IP that drifts from a pinned address, since
the VPN depends on the ISP's fixed IP. CPU load is left out of the
icon because spikes would flicker it. The four conky widgets are
removed once the panel is verified beside them.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
An edit now rewrites only the fields that changed. A save with nothing
changed used to rebuild the alarm, turning ACTION:AUDIO into DISPLAY
and dropping ACKNOWLEDGED, re-anchor the start to the local zone, and
strip SUMMARY's parameters; the test edits a foreign event unchanged and
checks every one survives.
get, edit and delete name the calendar the event is in. The same invite
synced into two calendars has one UID, and the panel acted on whichever
file came first, so editing one copy could overwrite or delete the
other.
A custom rule's date cannot be moved from the panel: BYDAY=MO stayed on
Monday while the start moved, and the series lost the day shown.
UNTIL is read back in local time, so a 22:30 series keeps its last
occurrence. Files are written 0644 like vdirsyncer's. Enter in the title
no longer bypasses the busy guard, which could create an event twice,
and a throwing callback no longer leaks its Process.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
The island README gains the panel. AGENTS.md records why calctl reads
the vdir itself, the local-time recurrence rule, the system Python it
needs, and two traps the build hit: a QML method named escape fails to
load, and a pill expanding for any panel grew beside the calendar.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
Checking a day's reminders meant opening each event. The bell shows
when the event carries its own VALARM, preset or custom. cal-notif's
per-calendar defaults are not reflected: they are its configuration,
not a property of the event.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
It expanded for any panel, which was right while it hosted every panel
there was. The calendar panel lives in the clock pill, so the status
pill grew into an empty box beside it. It now expands for its own two.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
A click on the pill opens the panel in its capsule, 620px wide, growing
left from the gap so the status pill does not move. Focus goes into the
panel so its text fields and Escape work; Escape closes the editor
before the panel.
The Escape hook is back(), not escape(): QML rejects a method named
escape with "Illegal method name", since it shadows the global JS
function, and the reload failed until it was renamed.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|