From fd9ecf4b9f9418a4279ac87b099b570b854f9bc6 Mon Sep 17 00:00:00 2001 From: rickpeters Date: Tue, 29 Sep 2026 17:07:52 +0200 Subject: [PATCH] feat: progress-report skill and scripts/vmprogress.sh (a status line per change); referenced from the other skills and AGENTS.md --- .claude/skills/cachyos-vm-testing/SKILL.md | 2 + .claude/skills/progress-report/SKILL.md | 64 ++++++++++++++++++++++ .claude/skills/steam-machine-iso/SKILL.md | 1 + .claude/skills/vm-install/SKILL.md | 3 + .claude/skills/wsl-build-host/SKILL.md | 4 ++ AGENTS.md | 6 +- scripts/vmprogress.sh | 45 +++++++++++++++ 7 files changed, 123 insertions(+), 2 deletions(-) create mode 100644 .claude/skills/progress-report/SKILL.md create mode 100755 scripts/vmprogress.sh diff --git a/.claude/skills/cachyos-vm-testing/SKILL.md b/.claude/skills/cachyos-vm-testing/SKILL.md index d58dd16..c3fef09 100644 --- a/.claude/skills/cachyos-vm-testing/SKILL.md +++ b/.claude/skills/cachyos-vm-testing/SKILL.md @@ -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 `) right away. **Show the app too**: start it on the VM's desktop (`systemd-run --user /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 diff --git a/.claude/skills/progress-report/SKILL.md b/.claude/skills/progress-report/SKILL.md new file mode 100644 index 0000000..71e4ad5 --- /dev/null +++ b/.claude/skills/progress-report/SKILL.md @@ -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-.test.log` / `~/vms/run-.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/` 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 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 --print`, package + virt-firmware) and compare with a loader that works. diff --git a/.claude/skills/steam-machine-iso/SKILL.md b/.claude/skills/steam-machine-iso/SKILL.md index 1a9e13b..65f84f3 100644 --- a/.claude/skills/steam-machine-iso/SKILL.md +++ b/.claude/skills/steam-machine-iso/SKILL.md @@ -35,6 +35,7 @@ setup during the install. Two repos: 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. +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 each new build's log by itself, so one window serves every build (check with diff --git a/.claude/skills/vm-install/SKILL.md b/.claude/skills/vm-install/SKILL.md index 6254d4a..ebcdcc6 100644 --- a/.claude/skills/vm-install/SKILL.md +++ b/.claude/skills/vm-install/SKILL.md @@ -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 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` Run this instead of doing the steps below by hand: `scripts/vmtest.sh [--install] [--window] [loader...]` diff --git a/.claude/skills/wsl-build-host/SKILL.md b/.claude/skills/wsl-build-host/SKILL.md index c620274..c3f2885 100644 --- a/.claude/skills/wsl-build-host/SKILL.md +++ b/.claude/skills/wsl-build-host/SKILL.md @@ -99,3 +99,7 @@ so it can be stopped: 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 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. diff --git a/AGENTS.md b/AGENTS.md index 093c5a3..7b74a9c 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -3,7 +3,8 @@ 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 `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) - 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 [args]` (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. -- 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. - 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. diff --git a/scripts/vmprogress.sh b/scripts/vmprogress.sh new file mode 100755 index 0000000..decd87e --- /dev/null +++ b/scripts/vmprogress.sh @@ -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% / / 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 : "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