feat: progress-report skill and scripts/vmprogress.sh (a status line per change); referenced from the other skills and AGENTS.md

This commit is contained in:
theupriser committed 2026-09-29 17:07:52 +02:00
1 parent fd1b916023
commit 3a0d9f98d8
7 files changed
+123 -2

No files matched your search

@@ -49,6 +49,8 @@ below), never hidden over SSH. When a run was started hidden anyway, open a
Konsole that follows its log (`tail -n +1 -f <log>`) right away. **Show the Konsole that follows its log (`tail -n +1 -f <log>`) right away. **Show the
app too**: start it on the VM's desktop (`systemd-run --user app too**: start it on the VM's desktop (`systemd-run --user
/mnt/ui/steamify-ui`) for the screens you test, and screenshot it. /mnt/ui/steamify-ui`) for the screens you test, and screenshot it.
Long unattended jobs (installs, `vmtest.sh`): report them as the
`progress-report` skill says.
## The VM on the Steam Machine ## The VM on the Steam Machine
+64
View File
@@ -0,0 +1,64 @@
---
name: progress-report
description: Use whenever a long VM job runs for the user (vminstall.sh, vmbootloadertest.sh, vmsuite.sh, vmtest.sh, an ISO build), locally or on the WSL PC, and the user wants to follow it - how to report progress (a table with a bar per VM and a total, only when something changes), show the log in the user's terminal and the VM's screen on their desktop, and look into a job that seems stuck.
---
# Progress report for VM jobs
What the user asked for (2026-09-29): see what is going on, without noise.
## The rules
- **Report only on a change**: an install stage, a test step, a job finishing, a FAIL. Never a
timed "no change" message. One monitor, not polling from the conversation.
- **Every report is the same table**, one row per VM/job plus a total row:
| VM | Step | Checks | Progress |
|---|---|---|---|
| grub | ✅ done | 40 / 40, 0 failed | `████████████████████` 100% |
| systemd-boot | test: kernel update | 27 / 40, 0 failed | `█████████████░░░░░░░` 68% |
| limine | install: desktop environment (40%) | 0 / 41 | `░░░░░░░░░░░░░░░░░░░░` 0% |
| **Total** | | **67 / 121**, 0 failed | `███████████░░░░░░░░░` 55% |
Bar: 20 cells, `█` per 5% of checks passed out of the expected count. Step in plain words
("install: base system (9%)", "test: reboot into the other kernel"), ✅ when done, ❌ with the
failed check's name when something fails. Under the table at most two lines: what is odd or next.
- **A FAIL or a job that stops moving is reported at once**, with the cause looked up first (below),
not only the numbers.
## The monitor
`scripts/vmprogress.sh [job...]` (jobs: limine systemd-boot grub cli menu hw installer toggles)
prints one line only when something changes and `ALLDONE` at the end; it reads the latest run in
`~/vms/bl-<loader>.test.log` / `~/vms/run-<suite>.log` and the install percentage from
`$VM_DIR/install-www/install.log`. Expected check counts live at its top: update them when a
suite gains checks. `--once` prints the current state.
On the WSL PC, from the laptop:
```
Monitor(command: "ssh wsl '~/projects/steamify-cachyos-dev/scripts/vmprogress.sh grub systemd-boot limine'",
description: "boot loader tests: only on change", timeout_ms: 1800000)
```
Re-arm it when it expires while jobs still run. Turn each event into the table above.
## What the user sees on the PC
- **Their terminal**: stream the running job's log into it (the `showlog` unit, `wsl-build-host`
skill); switch it when the job changes (install log, then the test log, then `~/vms/test.log`).
- **The VM's screen**: automated runs are headless. To show one: `scripts/vmview.py ~/vms/<vm>` in
a unit with the WSLg env (a window refreshed every 2 s, view only). When the user wants to watch
or step in, restart the job with a real window (`--window`, WSLg env) instead.
- One screenshot for yourself (`scripts/qmpshot.py <qmp.sock> out.png`, copied back and Read) only
to diagnose a stuck boot, not as a test.
## A job that seems stuck
1. `--once` and the log's last `#####` step: how long has it been there, compared with the others?
2. Is the VM up: `pgrep -af '[q]emu'` (its `hostfwd` port), ssh to it with the test's own options
(`. scripts/common.sh` with its `VM_DIR`/`VM_PORT`): a known_hosts mismatch or "Permission
denied" is a test setup problem, not the guest.
3. No ssh banner: take one screenshot. Firmware PXE/HTTP boot means no usable boot entry: read the
UEFI variables from a copy of `vars.fd` (`virt-fw-vars -i <copy> --print`, package
virt-firmware) and compare with a loader that works.
@@ -35,6 +35,7 @@ setup during the install. Two repos:
The user watches the Steam Machine over Moonlight: run builds and tests in a The user watches the Steam Machine over Moonlight: run builds and tests in a
Konsole on its desktop (or open one that follows the log), never hidden. Konsole on its desktop (or open one that follows the log), never hidden.
Progress in the conversation: the `progress-report` skill (a table, only on a change).
Open that Konsole only when none follows the log yet: `tail -F` picks up Open that Konsole only when none follows the log yet: `tail -F` picks up
each new build's log by itself, so one window serves every build (check with each new build's log by itself, so one window serves every build (check with
+3
View File
@@ -138,6 +138,9 @@ lose the executable bit (`chmod --reference` or call scripts with `bash`); a sui
be a `.host.sh` block; ssh has no Plasma session, the prelude exports one; a one-off network failure can fail be a `.host.sh` block; ssh has no Plasma session, the prelude exports one; a one-off network failure can fail
an install step (LED driver from the AUR), rerun the block before suspecting Steamify. an install step (LED driver from the AUR), rerun the block before suspecting Steamify.
Following a run for the user (a table per VM with a bar and a total, only on a change; their terminal and
the VM's screen): the `progress-report` skill, with `scripts/vmprogress.sh` as the monitor.
## Testing a boot loader: `scripts/vmtest.sh boot` ## Testing a boot loader: `scripts/vmtest.sh boot`
Run this instead of doing the steps below by hand: `scripts/vmtest.sh [--install] [--window] [loader...]` Run this instead of doing the steps below by hand: `scripts/vmtest.sh [--install] [--window] [loader...]`
+4
View File
@@ -99,3 +99,7 @@ so it can be stopped:
stop with `systemctl stop showlog` (Ctrl+C there doesn't). Tell the user stop with `systemctl stop showlog` (Ctrl+C there doesn't). Tell the user
not to type there while it runs. A header printed before a busy log scrolls not to type there while it runs. A header printed before a busy log scrolls
away at once. away at once.
Reporting progress (the table, only on a change), a headless VM's screen in a
window (`scripts/vmview.py`) and looking into a stuck job: the
`progress-report` skill.
+4 -2
View File
@@ -3,7 +3,8 @@
Test tooling for Steamify (`../steamify-cachyos`) and the Steam Machine ISO (`../steammachine-cachyos-live-iso`): Test tooling for Steamify (`../steamify-cachyos`) and the Steam Machine ISO (`../steammachine-cachyos-live-iso`):
VM scripts (`scripts/`, `run.sh`), the automated test (`scripts/vmtest.sh`, checks in `share/vmtest/` and VM scripts (`scripts/`, `run.sh`), the automated test (`scripts/vmtest.sh`, checks in `share/vmtest/` and
`share/bootloader-test/`), `TESTPLAN.md` (keep it current: rows and a results line after every run) and the `share/bootloader-test/`), `TESTPLAN.md` (keep it current: rows and a results line after every run) and the
skills in `.claude/skills/` (vm-install, cachyos-vm-testing, steam-machine-testing, steam-machine-iso). skills in `.claude/skills/` (vm-install, cachyos-vm-testing, steam-machine-testing, steam-machine-iso,
wsl-build-host, progress-report).
## Running the tests (do this, don't re-derive it) ## Running the tests (do this, don't re-derive it)
- Everything: `scripts/vmtest.sh --screen` (detached `screen` session `vmtest`), then read only - Everything: `scripts/vmtest.sh --screen` (detached `screen` session `vmtest`), then read only
@@ -11,7 +12,8 @@ skills in `.claude/skills/` (vm-install, cachyos-vm-testing, steam-machine-testi
`scripts/vmtest.sh cli hw`, `boot`, `limine`. From another machine: `scripts/vmtest-remote.sh <ssh-host> [args]` `scripts/vmtest.sh cli hw`, `boot`, `limine`. From another machine: `scripts/vmtest-remote.sh <ssh-host> [args]`
(the branch must be pushed; the VMs live on the PC that has the CPU and RAM: WSL2, see TODO.md R1b). (the branch must be pushed; the VMs live on the PC that has the CPU and RAM: WSL2, see TODO.md R1b).
- Read `.claude/skills/vm-install/SKILL.md` before touching the scripts; `TODO.md` has the open work. - Read `.claude/skills/vm-install/SKILL.md` before touching the scripts; `TODO.md` has the open work.
- Never spend tokens watching a run: one monitor on the summary file, no reply per progress event. - Following a run: one monitor (`scripts/vmprogress.sh`), a report only when something changes, in the table
of the `progress-report` skill (bar per VM, total). Never a timed "no change" message.
- Headless is for automated runs (default in `vmtest.sh`); a VM started by hand for the user has a window. - Headless is for automated runs (default in `vmtest.sh`); a VM started by hand for the user has a window.
- Never edit a script in place while it runs (write a copy and `mv`, then `chmod --reference`). - Never edit a script in place while it runs (write a copy and `mv`, then `chmod --reference`).
- Kill/pgrep patterns: bracket them (`[q]emu`) or your own shell matches itself. - Kill/pgrep patterns: bracket them (`[q]emu`) or your own shell matches itself.
+45
View File
@@ -0,0 +1,45 @@
#!/bin/bash
# Progress of test jobs, one line per change (for a monitor; see the progress-report skill).
# scripts/vmprogress.sh [--once] [job...] jobs: limine systemd-boot grub cli menu hw installer toggles (default all)
# Per job: state (install NN% <stage> / <test step> / done / -), checks passed/expected, failed.
# Line: "HH:MM total P/E F failed ;; job | state | P/E | F failed ;; ...". Prints nothing while nothing
# changes (checked every 30 s), "ALLDONE" and exits once every started job has its summary line.
# Expected counts: the last complete run of each (AGENTS.md "State"); update them when checks are added.
set -uo pipefail
declare -A expect=([limine]=41 [systemd-boot]=40 [grub]=40 [cli]=55 [menu]=36 [hw]=70 [installer]=4 [toggles]=42)
once=false; jobs=()
for a in "$@"; do [[ "$a" == --once ]] && once=true || jobs+=("$a"); done
[[ ${#jobs[@]} -gt 0 ]] || jobs=(limine systemd-boot grub cli menu hw installer toggles)
vms="$HOME/vms"
status() { # status <job>: "state|pass|fail|finished(0/1)|started(0/1)"
local j="$1" log dir
case "$j" in limine|systemd-boot|grub) log="$vms/bl-$j.test.log" dir="$vms/bl-$j" ;; *) log="$vms/run-$j.log" dir="$vms/run-$j" ;; esac
[[ -f "$log" ]] || { echo "-|0|0|0|0"; return; }
local p f st run
# The logs are appended to: only the latest run counts (from its "===== vm..." header on).
run="$(tac "$log" | sed '/^===== vm/q' | tac)"
p=$(grep -ac '^PASS' <<< "$run"); f=$(grep -ac '^FAIL' <<< "$run")
if grep -aq "^== $j: [0-9]* passed" <<< "$run"; then echo "done|$p|$f|1|1"; return; fi
st=$(grep -aE '^##### ' <<< "$run" | tail -1 | sed 's/^##### [0-9:]* //' | cut -c1-40)
if [[ "$st" == install* && -f "$dir/install-www/install.log" ]]; then
st="install $(grep -aoE '^\[ *[0-9.]+%\] [^.(]*' "$dir/install-www/install.log" | tail -1 | sed 's/^\[ *\([0-9]*\)[0-9.]*%\] /\1% /; s/ *$//')"
fi
echo "${st:-starting}|$p|$f|0|1"
}
prev=""
while true; do
line="" tp=0 te=0 tf=0 running=0
for j in "${jobs[@]}"; do
IFS='|' read -r st p f fin started <<< "$(status "$j")"
[[ "$started" == 1 && "$fin" == 0 ]] && running=$((running + 1))
tp=$((tp + p)) tf=$((tf + f)) te=$((te + ${expect[$j]:-0}))
line+=" ;; $j | $st | $p/${expect[$j]:-?} | $f failed"
done
cur="total $tp/$te $tf failed$line"
[[ "$cur" != "$prev" ]] && { echo "$(date +%H:%M) $cur"; prev="$cur"; }
$once && exit 0
[[ $running -eq 0 ]] && { echo ALLDONE; exit 0; }
sleep 30
done