mirror of
https://github.com/kuhyx/steam-backlog-enforcer.git
synced 2026-11-10 18:07:07 +01:00
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
5.8 KiB
5.8 KiB
Move every run.sh command into the React web UI
REMOVE ME AFTER FINISH
Spec agreed with the user on 2026-10-10 (grilling rounds in session
session_01M3QPamsDnLQyQ6g4rresQf). Contract: DOCS-web-control-api.md +
web/src/api/contract.ts.
what
A production-quality React/TS UI that covers ALL 24 CLI commands (views,
jobs with live progress, setup wizard, daemon + server health), so nobody
has to type ./run.sh <cmd>. The CLI stays as backend/recovery path; bare
./run.sh opens the UI.
must
- Privileged ops go through the root daemon's
ctl.sock(SO_PEERCRED); the web server never gets root. - Friction enforced server/daemon-side (phrases, gaming-reset 300 s heartbeat countdown, unblock cap, 24h exception lock). More friction, not less.
- must not: any way to stop/disable the enforcer (UI, CLI or socket). Restart only, rate-limited, after a state flush.
- Long ops: profile on scratch state, fix top hotspot each, determinate progress (step N/M, item, ETA) for anything >2 s.
- Stack: React 19 + React Compiler + TanStack Router/Query, newest stable,
exact pins; tokens from
~/src/utils/unified-design-system; keyboard operability per itsDOCS-operability.md. .desktopentry opening a Chrome--appwindow (never port 9222).
done
- Every command has a working UI control, driven in headless chromium against a scratch state dir, with a screenshot each; one live pass of status + done.
- Before/after timing table for long ops, none slower.
- vitest 100 % on
web/src, pytest 100 % on new Python modules, pre-commit + dependency-freshness green. - Daemon socket: passed in vmbox, then deployed (
sudo ./install.sh, daemon restarted) and verified live.
status
- contract frozen
- A: Python job runner + Progress/Prompter refactor of input() sites (applied to main tree, uncommitted; CLI "Type YES" → friction phrases)
- B: root daemon ctl.sock + two-phase privileged ops — passed in vmbox,
NOT deployed to host yet (needs
sudo ./install.sh+ daemon restart) - C: frontend shell + all screens against mocked backend (landed;
contract split into contract.ts + jobContract.ts for the 250 cap;
npm run dev:mockruns it against web/mock) - D: server write endpoints, auth, SSE, views, catalog; wire A+B
- D2: integration fixes (arm phrase, not_found/server_stale, dev proxy, token reload, per-port token, job ordering/locked-vs-busy/spawn fail, save_credentials keeps settings)
- user decided (Q16):
resetnever unblocks the store, CLI or web —release_storeflag and web_resetwrapper removed; verified on scratch HOME (tests in test_main_misc* will need updating) - E: profile + optimise long ops — check ~4x (tampering re-fetch 20 in
flight + early stop), scan −23% after the no-achievements skip cache
warms (
_achievement_skip.py), scan cancel 71 s → 1 s, stats −1.7 s (HLTB search-URL memo). Coordinator fix: skip cache only records Steam's explicit 400 "no stats", never timeouts/5xx (verified). - user request: "Pick my own game…" in list/done prompts (
_own_pick.py), cancel any job waiting on a prompt (cancel.request marker) — verified - G: VERIFIED 2026-10-10 — scratch HOME (grid 1369, "wicher" →
Witcher 1/2/3, scroll 0 dropped frames p95 16.8 ms, filters, pick-mode
re-ask/back/cancel, mock mode) + vmbox guest
sbe-g(own-pick → Witcher 2 assigned in a real pick job, API + browser). Screenshots /tmp/sbe-g/. Pick submits only via the "Pick …" button (no double-click assign). Owned-cachehas_stats+ records survive only once the daemon runs G code (H deploy). Awaiting user confirmation. - G (spec): Steam-like library browser (user spec Q21–Q26, 2026-10-10, all as
recommended): new Library page grid of ALL owned games with cover art,
same component replaces the own-pick text prompt (new prompt kind
game; CLI keeps text search); ineligible games greyed with reason; art = Steam librarycache (~/.local/share/Steam/appcache/librarycache/ <appid>/<hash>/library_capsule.jpg, 558 games) → server-side CDN fetch + disk cache (shared.cloudflare.steamstatic.com/store_item_assets/ steam/apps/<id>/library_600x900.jpg, not store-blocked) → title tile; lazy images; fuzzy typo-tolerant search + top-8 suggestion dropdown, Enter/arrows, roman↔arabic numerals; card: cover, title, ach %, HLTB h, playtime, installed/assigned badges; sort name/recent/completion/HLTB; filters hide-completed/installed/pickable. BUILT 2026-10-10 (uncommitted):_web_library.py,_web_art.py, owned-cachegamesrecords,ineligible_reason+GamePicker/JobPrompter.game, web/src/library/*, jobs/GamePrompt.tsx, Library.tsx toggle, styles/library.css. Scratch verification + mock + DOCS update delegated; own-pick end-to-end runs in a vmbox copy of the enforcer (user, 2026-10-10: never live). DONE: grid lists all ~1369 owned games with smooth scroll, "wicher" → Witcher 1/2/3 in suggestions, own-pick from the browser in a live Check-now job assigns the game. - H: deploy DONE 2026-10-10 15:23 (
sudo install.sh+ daemon restart, ctl.sock live; gaming-reset arm → heartbeat → cancel verified live, 204/410). STILL TODO: every-screen screenshot pass (real server, scratch HOME) + one live status + done pass. - tests: pytest 2707 pass, 100 % line+branch; vitest 523 pass, 100 % (React Compiler off under vitest only: its memo-cache branches are unreachable for coverage)
- F: run.sh bare → UI (
scripts/open_ui.sh), .desktop entry (install.shinstall_desktop_entry) — opened live, WM class verified - F2: live verification of the finished UI
- user confirmation → tests, coverage, pre-commit, commit (2026-10-10)