feat: hook reliability, hook-errors setting, sparse config, and logging

Hook reliability:
- Add hook-errors = "warn" | "fail" setting (default: warn); in fail
  mode, abort launch when pre-launch hook exits nonzero or can't execute
- Ensure post-launch hook runs unconditionally, even when execute_wait()
  fails to spawn the game
- Propagate game's real exit status via std::process::exit(); report
  post-hook failures clearly to stderr
- Centralize hook execution via run_hook() helper (sh -c)

New features in this batch:
- Sparse config and profile support: only configured fields are written;
  unset fields fall back through profile → global chain
- config show --effective flag: renders the fully-resolved view
- Config migration: upgrades legacy flat config to current schema
- Structured decision logging (src/log.rs) for session-level audit trail
- Gamescope improvements: additional flags and validation
- CHANGELOG.md tracking template releases

Schema / UX:
- HookErrors enum (Warn/Fail) added to Settings and ResolvedSettings
- hook-errors key in keys.rs, mod.rs rendering, completion candidates,
  doctor output, help text, README, and dry-run display
- 9 focused tests covering warn/fail behavior, exit propagation,
  round-trip (set/show/reset), profile round-trip, export/import

Co-Authored-By: claude-flow <ruv@ruv.net>
This commit is contained in:
2026-06-14 09:35:24 -04:00
parent a2364b1692
commit f984acf0e3
21 changed files with 4070 additions and 1105 deletions
+95 -3
View File
@@ -33,7 +33,7 @@ Implemented features:
- Steam-first launcher flow with `gamewrap %command%`
- Default launch mode with MangoHud and GameMode
- Friendly setting names for all launch options
- Named profiles with full inheritance chains and cycle detection
- Named game-specific profiles (flat two-tier: global defaults + per-game overrides)
- Per-profile environment variable overrides (`profile env set/unset/list/clear`)
- Manual executable-to-profile bindings
- Observed game history with launch count, timestamps, and display names
@@ -51,14 +51,13 @@ Implemented features:
- `dry-run` launch plan preview
- `config edit` to open config in `$EDITOR`
- Config and profile export/import for sharing
- `profile tree` for visualizing inheritance chains
- `notify test` for graphical notification verification
- ANSI color output (respects NO_COLOR, CLICOLOR, CLICOLOR_FORCE)
- Shell completion with live candidates (profiles, games, settings)
- Clear runtime dependency checks and actionable error messages
Friendly settings supported:
- `overlay`, `performance`, `steam-host-libs`, `game-libs`, `verbose`
- `mangohud`, `gamemode`, `steam-host-libs`, `game-libs`, `verbose`
- `gamescope`, `gamescope-width`, `gamescope-height`, `gamescope-fps`
- `fps-cap`, `vkbasalt`
- `esync`, `fsync`, `large-address-aware`
@@ -132,6 +131,7 @@ Features that were deferred from the initial scope and are now implemented:
Features still deferred:
- Benchmark and recording profile presets (named templates that bundle several settings)
- Additional launcher helpers beyond the current set
- **Profile description field for community sharing** — add `description: Option<String>` to `ProfileConfig` and `SharedProfileFile`, shown at the top of exported `.gamewrap-profile.toml` files so ProtonDB/forum posts are self-documenting. CLI: `gamewrap profile describe <name> <text>` and `profile clear-describe <name>`. Preserved through import and shown in `profile show`/`profile list`. No tags, AppIDs, or author fields — those belong on the posting platform, not in the file.
## Recommended Expansion Order
@@ -245,3 +245,95 @@ Before starting packaging or deferred features, re-check:
- whether the project is going public
- whether package maintenance is worth the overhead
- whether v1 behavior is stable enough to freeze the main CLI/config model
---
## Post-v1 Backlog
Logged 2026-06-06. Priority order reflects dependencies — B1 sets naming used by B5, and JSON output (B6 Phase 1) is prerequisite for any GUI work.
### B1 + B4 — Settings grouping, tool-prefixed names, help system overhaul
**Problem:**
- `gamewrap help settings` outputs 36 settings in a flat, ungrouped list with no visual separation by tool
- `overlay` (MangoHud) and `performance` (GameMode) have no tool prefix while every gamescope/vkbasalt/mangohud-log setting already does
- A gamescope configuration note currently sits orphaned between log options and the gamescope settings block in help output
**Proposed changes:**
- Rename `overlay``mangohud` (the MangoHud enable/disable toggle), consistent with `mangohud-log`
- Rename `performance``gamemode` (the GameMode enable/disable toggle)
- Group `gamewrap help settings` into tool-based sections: **Core**, **MangoHud**, **GameMode**, **Gamescope**, **vkBasalt**, **Proton/Wine**, **Hooks & Logging**
- Move the gamescope configuration note into the Gamescope section header (fixes B4)
- Enhance `topic_text()` in `src/help.rs` to accept an optional tool filter: `gamewrap help settings gamescope`
- Propagate renames everywhere: `Settings` struct fields, CLI parser, `config/keys.rs`, TOML serialization, shell completion, tests, README, docs
- Add a migration path for existing configs using the old names (clear error pointing to new name, or silent rename on load)
**Note:** Breaking change — existing config files and profiles using `overlay` or `performance` will need migration. Sets the naming foundation for B5.
**Key files:** `src/help.rs`, `src/config/schema.rs`, `src/config/keys.rs`, `src/config/mod.rs`, `src/cli.rs`, `src/completion.rs`, `tests/`, `README.md`
---
### B2 — Large game list management
**Problem:**
- After using gamewrap on many games (demos, uninstalled games, one-offs), `game list` grows without bound
- The only removal option is `game forget` (hard deletion); no way to soft-hide entries
**Proposed changes:**
- Add `game archive <name-or-exe>` / `game unarchive <name-or-exe>` — sets an `archived` flag on the state entry, excluded from default `game list`
- `game list --all` shows archived entries alongside active ones (visually marked)
- `game forget` remains for permanent removal
- `game list` shows an entry count and a hint if the list exceeds a threshold (e.g. 20 entries)
**Key files:** `src/cli.rs`, state file handling in `src/config/mod.rs`, `src/detect.rs`, tests
---
### B3 — Profile export semantics
**Question:** When a profile is exported to share:
- **Option A — sparse:** Export only what was explicitly set in the profile. Recipient's globals fill the rest at their end. Simple and portable; behavior depends on recipient's global config.
- **Option B — effective:** Export fully resolved settings (profile + globals baked in). Recipient gets a "known good" snapshot but must manually strip their own preferences.
- **Option C — sparse + informational context:** Export sparse profile, plus a `# context:` comment block showing what the exporter's globals were at export time. Informational only — not interpreted by import.
**Current behavior:** Option A (sparse).
**Resolved:** Sparse export implemented. Profiles are now flat (no inheritance). Export produces only explicitly set settings.
---
### B5 — Grouped, cleaner `config show` / `profile show` display
**Problem:**
- `config show` output (especially `--effective`) has no visual grouping — 30+ settings appear in struct field order
- No section headers separating e.g. gamescope settings from MangoHud settings
**Proposed changes:**
- Refactor `render_resolved_settings()` and `render_profile_settings_with_indent()` to emit settings under dimmed section headers using the same tool groups as B1
- Configured mode (default): only show a section header if that section has at least one configured value
- Effective mode (`--effective`): always show section headers; show `(nothing configured)` per-section if empty
**Dependency:** Best done after B1, which defines the canonical section groupings. Can be scoped independently by hardcoding groups if B1 is deferred.
**Key files:** `src/config/mod.rs`, tests
---
### B6 — JSON output flag + GUI (discussion needed)
**Phase 1 — JSON flag (independent):**
- Add `--json` flag to read commands: `config show`, `profile show`, `game list`, `status`, `dry-run`
- Write/mutating commands return `{"ok": true}` or the updated state on success
- Useful for scripting independently of any GUI
**Phase 2 — GUI (dependent on Phase 1):**
- Build a GUI that invokes `gamewrap` as a subprocess and renders the JSON output
- CLI remains the authoritative source of truth; GUI is a frontend only
**Discussion points before Phase 2:**
- Framework: egui (Rust, self-contained), iced (Rust async), Tauri (web frontend, heavier), GTK4 (gtk-rs)?
- Scope: full settings editor, profile manager, game list browser, or read-only status overlay?
- Packaging: GUI as an optional Cargo feature flag to keep the base CLI install slim?
**Recommended starting point:** Phase 1 JSON flag only.