42 Commits
Author SHA1 Message Date
Felitendo 776a39074d docs: show new ui as screenshots in the readme 2026-09-28 15:08:14 +02:00
Felitendo c5a4ffbe08 chore: 1.3.2 v1.3.2 2026-09-28 14:40:06 +02:00
Felitendo 1078bd52ab fix: hide the progress bar when start notices are off
Fixes #2
2026-09-28 14:40:00 +02:00
Felitendo 9a471a005d chore: show feature requests before bug reports 2026-09-26 21:19:28 +02:00
Felitendo b78f1629ad chore: commit different topics separately 2026-09-25 09:30:38 +02:00
Felitendo 0f5e41cc5c chore: switch to ko-fi 2026-09-24 13:21:19 +02:00
Felitendo 1e02e0dfa8 chore: add issue templates 2026-09-24 12:39:49 +02:00
Felitendo 47d5862b5f docs: commit and push only after a local check 2026-09-24 08:42:01 +02:00
Felitendo f4b7a26dec chore: 1.3.1 v1.3.1 2026-09-24 02:01:04 +02:00
Felitendo 7cd6eafafe docs: cut the readme down, fold the details 2026-09-24 02:00:35 +02:00
Felitendo 08ffaad00b fix: say 1 minute ago, not 1 minutes ago 2026-09-24 02:00:35 +02:00
Felitendo 1f0fb22d1c docs: show the menu as real screenshots 2026-09-24 02:00:35 +02:00
Felitendo b4038baf5b docs: add a changelog and the release notes flow 2026-09-24 02:00:35 +02:00
Felitendo d2b04f66ea docs: add commit rules to claude.md 2026-09-24 01:13:07 +02:00
Felitendo f1b7658e82 docs: coffee button and bug report link 2026-09-24 01:13:07 +02:00
Felitendo 6dd674c05f chore: switch funding to buy me a coffee 2026-09-24 01:13:07 +02:00
Felitendo b1e1cf0b54 docs: add icon and centered readme header 2026-09-21 14:58:44 +02:00
Felitendo c40dfe0238 docs: add claude.md and avoid dashes 2026-09-21 14:00:02 +02:00
Felitendo dbdbfe5cd5 chore: move to LoonixTools 2026-09-21 13:07:21 +02:00
Felitendo 368c741d99 docs: trim the readme to the essentials 2026-09-04 12:55:25 +02:00
Felitendo 162b30ba38 cachy-auto-update 1.3.0
The progress bar stops freezing on a count it made up, drops the steps that
have no work, and carries the run log's last lines under Details.
v1.3.0
2026-08-20 19:57:40 +02:00
Felitendo c8666da714 Show the run log's last lines under Details, live
The percentage says an update is alive. It does not say what it is alive
doing, and for the longest stretch of a run there was no way to find out:
an AUR package compiling for a quarter of an hour talks constantly, and
every word of it went into a file nobody was looking at.

So the run log's last five lines now travel with the progress entry and
sit under Details, refreshed every two seconds for as long as the update
lasts. Polled rather than followed, for the same reason the pacman
watcher polls: only the last few lines are ever displayed, so every line
in between would be work nobody sees, and re-reading the tail whole makes
truncation and rotation of the log a non-event.

The job model behind this interface carries exactly two description
fields - descriptionValue1 and 2, there is no third - so one stays with
the package being worked on and the other takes the tail. Newlines inside
a field do render, which is what lets five lines share one of them. They
travel tab separated because the protocol is one instruction per line,
and a tab inside a log line becomes a space first: either renders as
whitespace, but a line split in half renders as nonsense. Five lines
clipped to 120 columns also keeps an instruction well inside PIPE_BUF,
which is what makes the write atomic against the runner sending its own
progress down the same pipe.
2026-08-20 19:55:43 +02:00
Felitendo f9cd8a0ace Keep the progress bar moving for the whole run
Three stretches of a run had no way to report anything, and the bar
handled each of them badly.

pacman prints nothing at all between "starting full system upgrade" and
the transaction it eventually prepares. On a 161-package backlog that
silence ran to three minutes and nineteen seconds, and the bar spent all
of it frozen on "0 of 161" - a counter seeded from checkupdates before
there was anything to count. Working out the upgrade is now a step of its
own, with a label and deliberately no item count, because the number was
the part that was lying.

A step that turns out to have no work is dropped from the bar instead of
being handed its share for nothing. Packages already in the cache are
never announced by pacman, so a run that only has to unpack used to jump
thirty points the moment unpacking started; the same went for AUR with
nothing pending and for machines with no Gear Lever or no Flatpaks.

pacman's output is line-buffered through stdbuf. Writing to a log rather
than a terminal, libc released it in 4KB blocks - around a hundred and
sixty "upgrading foo..." lines at a time - so the bar sat still and then
leapt to the end of the step in one poll.

What is left is work whose length genuinely cannot be known: resolving a
transaction, and an AUR helper compiling for a quarter of an hour. Those
now creep along a curve that approaches the end of their step without
reaching it. The item counter stays put throughout - it is the field that
would be lying if it moved - and any real report overtakes the creep. A
bar that has not moved since it appeared is read as a hang, and somebody
who reads it that way reaches for the power button mid-update.

The bar is also monotonic now. Dropping a step rescales the run, and the
conflict-recovery loop restarts pacman and its tally from the top; both
are honest, neither is a reason to show a bar that retreats.
2026-08-20 19:45:56 +02:00
Felitendo 8834abe648 cachy-auto-update 1.2.2
The progress bar counts the download as well as the transaction, and every
step says outright that an update is running.
v1.2.2
2026-08-14 14:25:11 +02:00
Felitendo b796b2711a Move the bar while packages are downloading
The progress entry sat at "0 von 123" for the whole download and only
started counting once pacman began unpacking - which on a domestic line is
most of the run spent looking like nothing was happening. What was being
watched for was the transaction, and the transaction had not started yet.

Downloading is now a step of its own, worth 30 of the bar against the
transaction's 40, counted the same way: one line per package out of
pacman's "foo-1.2-1-x86_64 downloading...". The database sync just before
it prints the identical shape with the suffix that would give it away
already stripped, so the tally starts only after the ":: Retrieving
packages..." header. Packages already in the cache never announce
themselves, so the step regularly ends short of its total and hands the
rest of its share over when unpacking begins.

The headline follows: "Updates werden heruntergeladen", then
"Systempakete werden aktualisiert".
2026-08-14 14:22:05 +02:00
Felitendo 6538c1510d Say on the progress bar that this is an update running
The headline read "Paketquellen" over KDE's own "0 von 123 Elementen" -
two nouns and a count, with nothing anywhere saying that the machine was
updating itself. Nobody goes looking for this entry; it turns up beside
whatever they were doing, so it has to explain itself in one line.

Each step now says so outright: "Systempakete werden aktualisiert",
"Flatpak-Programme werden aktualisiert", and so on.

The count line underneath belongs to Plasma, which only counts in bytes,
files, dirs or items - "Paketen" is not on offer, so "Elementen" stays,
now under a headline that says what is being counted.
2026-08-14 14:13:54 +02:00
Felitendo ea3f0d21fa Make the progress bar follow the transaction it was supposed to be watching
It sat at "0 of 218 items" for an entire run. The watcher looked for
"(120/218) upgrading foo", which pacman only prints when it is drawing its
progress bar - and the unattended runs this exists for are precisely the ones
started with --noprogressbar, where it instead prints "upgrading glibc..." with
no counter at all. So nothing ever matched and the position never moved.

Both shapes are handled now. Where there is no counter the packages are tallied
here, one line each, and the total is read from the "Package (218)" header
pacman prints before it starts - a better number than checkupdates gives, since
that counts packages with an update available and knows nothing about new
dependencies pulled in alongside them. Replayed against a real 218-package run
from the log: 63, 137, 215, 218 of 218, with the package name in each step.

Offer to switch off CachyOS's reboot notification while enabling. cachyos-hooks
ships a PostTransaction hook that pops up "Reboot recommended!" the moment a
kernel, driver or systemd package is unpacked. That is fine for a manual
upgrade, where the transaction is the last thing happening. In an unattended
one it lands mid-run, with AUR packages still to build and Flatpaks still to
pull, and asking for a restart there is an invitation to cut the update in
half. Overriding the hook by name from /etc/pacman.d/hooks is the standard way
to switch a distribution hook off and is undone by deleting the link.

Offered rather than done, like the existing cachy-update prompt: it is another
package's behaviour and it applies to manual upgrades too.
v1.2.1
2026-08-14 11:34:03 +02:00
Felitendo 6aa9b147b8 Put a progress bar on the desktop, and repair the notifications around it
An unattended run takes twenty minutes and said nothing at all while it worked.
The notification area now carries a live entry for the duration - which step is
running, which package is being unpacked, item count, percentage. It is a job
in the sense of org.kde.JobViewServer, the same mechanism Dolphin uses while
copying files, rather than a notification, which is what makes it a real bar
instead of a line of text.

That mechanism needs a process of its own. The desktop ties a job to the D-Bus
connection that requested it and withdraws it the moment that connection
closes, so gdbus, busctl and dbus-send cannot drive one at all - every
invocation is a fresh connection that closes again immediately. A small helper
therefore runs inside each graphical session for the length of the update,
holding the connection open and taking instructions on stdin. It needs
python-gobject; without it there is no bar and nothing else changes. Position
within the repository step is read from pacman's own "(120/260) upgrading foo"
lines. Its other (n/m) sequences are ignored on purpose: checking keys, package
integrity and loading files each count up to the same total, and following them
would run the bar to the end three times before the first package was unpacked.

The "system updated" notification never arrived, which is what prompted looking
at any of this. Tagged notifications were posted with --replace-id naming the
start message, and Plasma silently drops a Notify() whose replaces_id points at
an expired notification: no bubble, no error, and the id it hands back is the
dead one it just ignored. The start bubble times out in seconds and a run lasts
minutes, so the result fell into exactly that hole every single time. The
previous message is now withdrawn and a fresh one posted.

How long a message stays is set per message rather than left to the daemon.
Anything reporting that the machine still needs a person - a failed update, a
locked package database, packages that had to be held back - waits until it is
dismissed. Everything else times out on its own, a successful update included;
nothing should have to be clicked away for having gone right. Daemons do keep
critical-urgency messages up and the specification asks them to, but that is a
should, it says nothing about the normal-urgency messages here that still need
somebody to act, and urgency separately governs sound and do-not-disturb.

"Restart recommended" is gone, and NotifyReboot with it. The running kernel
loses its module tree the moment pacman unpacks the new one, so the notice
fired while the run was still building AUR packages and pulling Flatpaks, where
it reads as an invitation to restart in the middle of an update. The state is
still recorded and cachy-auto-update status still reports it. The option went
rather than only its default, because an installed system keeps its own
configuration file and would have carried on notifying regardless.
v1.2.0
2026-08-14 10:49:02 +02:00
Felitendo a17aed4b3d Lower the battery threshold to 30% and default the cachy-update prompt to yes
The prompt offering to silence cachy-update's own update notification now
defaults to yes: once updates install themselves that notification is nothing
but noise, so the common answer should be the one you get by pressing Enter.

It also accepts "j" now. The prompt is translated, so a German user reads
"[J/n]" and types the German letter - which the old check for "y" alone
silently read as a refusal.
v1.1.2
2026-08-08 16:30:20 +02:00
Felitendo 2fa830284e Make the settings screen redraw 50x faster
Arrow-key navigation took 435 ms per keypress, which reads as the whole console
reloading on every press - because it effectively was. The cost was forks: each
frame ran a command substitution per label for the value, the translation and
the rendered state, 54 subshells for eighteen rows.

The frame is now assembled in memory and written once. Translations, the split
specs and the terminfo clear string are resolved before the loop; values are
re-read only after something actually changes, not on cursor movement. Helpers
on that path assign to a variable instead of printing, since printing is what
forced the substitution.

Measured on the same machine: 435 ms -> 7.5 ms per keypress.
v1.1.1
2026-08-08 16:25:09 +02:00
Felitendo c308b7e286 Add a settings screen so nothing needs a text editor
All eighteen options are now reachable from the menu as a cursor list: arrows
select, Space or Right cycles a value, q goes back, changes are written
immediately. A numbered menu would have run out of digits.

Three real bugs surfaced while building it, each found by testing against an
actual pty rather than a pipe:

- Labels went through printf as format strings, so the percent sign in
  "Minimum battery level (%)" was an invalid conversion. cau_msg_in now only
  treats a message as a format string when arguments were actually passed -
  otherwise any literal % a translator writes is a trap.

- Mixing bash's line-mode read into a single-key interface left the following
  read -sn1 receiving nothing at all, reproducibly, so the screen froze after
  editing the package list. Replaced with a small line editor built on the same
  single-character reader.

- Backspace was being swallowed: in canonical mode DEL is the ERASE character
  and the line discipline consumes it, and bash returns to canonical mode
  between each read -sn1. The interface now holds non-canonical mode for its
  whole lifetime and hands the terminal back only around actions that print or
  prompt, with a trap restoring it on Ctrl-C.

Translations and config reads are memoized; the screen redraws every label on
every keypress and a fork per lookup was the reason the redraw was slow enough
to matter.
v1.1.0
2026-08-08 16:18:59 +02:00
Felitendo 2eff62f9fd Say an update is running before it starts, not only after
Asked what happens if someone shuts the laptop down mid-update, the honest
answer turned out to be poor. The inhibitor does stop them - logind refuses and
falls back to org.freedesktop.login1.power-off-ignore-inhibit, which is
auth_admin_keep - so the desktop answers with an administrator password prompt
reading "Power off the system while an application is inhibiting this". systemd
ships that string untranslated, it never mentions updates, and no KDE catalog
contains any shutdown-blocked text at all. Only systemctl names the reason.

So a notification now goes out before the transaction, asking for the machine to
be left on. Notifications gained a tag: the result replaces the start message in
place rather than stacking a second, contradictory bubble beside it.

Tagged notifications also carry a queue flag. "An update is starting" is only
meaningful while somebody is looking, so unlike the result it is not spooled for
delivery at next login.
v1.0.9
2026-08-08 15:48:55 +02:00
Felitendo 0f91a79ba6 Recover from a pacman lock left behind by a power cut
A machine switched off mid-update leaves /var/lib/pacman/db.lck behind. Nothing
removed it, so every subsequent run deferred on it - one power cut would have
stopped updates permanently and silently, which on an unattended machine is the
worst outcome there is.

A lock older than the current boot is provably abandoned: no process that could
hold it still exists. Those are now removed and the interrupted upgrade is
repeated, with pacman reinstalling anything caught half-written. A lock that is
merely unheld within the same boot stays untouched and is only reported, since
removing it could corrupt a live transaction; the boot-time test is what makes
the difference between a proof and a guess. A fuser check is kept alongside it
so a backwards clock jump cannot make a live lock look abandoned.

Documented what each layer can actually promise: suspend and normal shutdown
are blocked by the existing inhibitor, a hard power-off cannot be prevented by
anything, and snap-pac's pre/post snapshots remain the backstop.
v1.0.8
2026-08-08 15:40:07 +02:00
Felitendo 6514c4d859 Trim the package cache by default, and split it from orphan removal
CleanCache was off, so nothing ever pruned /var/cache/pacman/pkg - 23 GB on the
machine this was found on, with three 3.2 GB copies of one package. Trimming
only drops older versions of installed packages and cached versions of
uninstalled ones, so the cost is downgrade depth, not working software.

flatpak uninstall --unused moves from CleanCache to RemoveOrphans, where it
belongs: unused runtimes are the Flatpak equivalent of orphaned packages, and
removing installed software should not hide behind a flag named for cache
trimming. RemoveOrphans stays off - 'orphaned' only means nothing depends on
it, which is also true of something installed deliberately.

The log now reports what a trim reclaimed, since a real paccache run says
almost nothing and there was otherwise no way to tell it was working.
v1.0.7
2026-08-08 15:33:03 +02:00
Felitendo 243115ea19 Show what a run is doing, and record when one is cut short
A run that held back a blocker then upgraded 214 packages printed one line and
then nothing for nearly five minutes while pacman downloaded and installed. It
looked hung, so it got killed - during pacman's uninterruptible commit phase,
which meant the packages landed but our bookkeeping never did. The menu then
kept showing a failure from a previous run on a fully up-to-date machine.

pacman, the AUR helper and flatpak now stream their output when a person is
watching, and the progress bar is left enabled for that case. Timer runs are
unchanged: quiet, --noprogressbar, everything captured in the log.

Interactivity is decided once at startup rather than tested at the point of
use. cau_pacman_flags runs inside a process substitution, so its stdout is
always a pipe and a -t 1 check there would have silently always been false.

INT/TERM/HUP now record last_result=interrupted, so a run that is stopped says
so instead of leaving the previous verdict standing.
v1.0.6
2026-08-08 15:24:42 +02:00
Felitendo 9fd2458d20 Hold back blocking packages instead of failing the whole upgrade
A repo package that replaces something an installed AUR package still depends
on aborted the entire transaction, and would have done so on every subsequent
run - one stale AUR package was enough to cut a machine off from all updates
indefinitely. Observed in the wild: percona-server-clients replaces
libperconaserverclient without providing it, while heidisql-qt6-bin hard-depends
on it, blocking 213 unrelated package updates.

pacman names the offending package in its dependency errors, so it is now
extracted and passed to --ignore for one retry: the other 213 packages go
through and the blocker is reported. The hold is per-run, never written to
IgnorePkg, so it disappears by itself once upstream catches up.

The single retry is also now a bounded recovery loop, because fixing one
problem regularly uncovers the next - a conflict resolved with --ask=20 can
surface a dependency error behind it. Each remedy is applied at most once.

The held-back set is shown in the menu and notified only when it changes, so a
blocker waiting on an upstream fix does not produce the same message daily.
v1.0.5
2026-08-08 15:12:43 +02:00
Felitendo f593cc1933 Menu: flip the switches without asking for a keypress
Toggling automatic updates or notifications returned to a 'press any key'
prompt for no reason - the status block at the top of the menu already shows
the new state. cau_bad and cau_note now flag that they printed something, so
the acknowledgement only appears when there is genuinely something to read
(a failed sudoers check, a missing AUR helper) instead of after every toggle.
v1.0.4
2026-08-08 15:05:38 +02:00
Felitendo 20fbadbc95 Menu: act on a single keypress instead of waiting for Enter
Also stops Enter from quitting the menu (it used to share the quit branch with
q) and swallows the tail of an escape sequence, so one arrow key redraws once
rather than three times and never closes the menu.
v1.0.3
2026-08-08 14:58:28 +02:00
Felitendo e42fb4f61c Make the reported version follow the version actually being built
VERSION is now overridable, so the PKGBUILD passes $pkgver into make and the
two can no longer disagree. v1.0.1 shipped a Makefile that still said 1.0.0, so
'cachy-auto-update --version' reported the wrong release.
v1.0.2
2026-08-08 14:45:07 +02:00
Felitendo 459cbbf8e7 Fix locale handling, menu re-entry and empty-checkupdates logging
- The runner now forces LC_ALL=C itself instead of relying on the unit's
  Environment=. pacman failures are classified by matching its output, so a
  run started by hand on a German system was misclassifying every failure.
- 'Update now' in the menu exec'd the runner, which terminated the menu.
- Log a distinct message when checkupdates is unavailable, instead of
  claiming zero pending packages before a full upgrade.
v1.0.1
2026-08-08 02:35:34 +02:00
Felitendo ceb024d7be Add cachy-auto-update: unattended background updates for CachyOS
A root systemd service applies pacman, AUR, Flatpak and AppImage updates on
its own, gated on battery state, gaming activity and whether anybody else is
using the package system. The CLI is deliberately two switches plus status.

No user password is stored anywhere: pacman runs as root directly, and the AUR
step - which makepkg forbids running as root - drops to a locked system account
that sudoers permits to call pacman without a password.
v1.0.0
2026-08-08 02:27:04 +02:00
Felitendo 327da1dae3 Initial commit 2026-08-08 01:29:40 +02:00