Files
linux-game-manager/.codex/skills/linux-game-manager-dev/references/game-extension.md
2026-02-22 06:30:55 -05:00

4.1 KiB

Game Extension Workflow

Use this workflow whenever adding, renaming, removing, or substantially changing a game.

Add a New Game

  1. Create installer script:
  • Path: .install/<Game Name>.sh
  • Keep first line active (do not start with #//).
  • Reuse manager helpers (check_architecture, check_dependencies, download, download_named, get_installer, ui_*).
  • Install into a deterministic path under ${installPath}.
  1. Create launcher definition:
  • Path: .launch/<Game Name>.game
  • Keep base filename identical to installer (<Game Name>).
  • Include an explicit install-path variable based on installPath, for example:
gamePath="${installPath}/MyGame"
  • Run the game from that path.
  1. Optional update script:
  • Path: .update/<Game Name>.sh
  • Implement run_update() (required by update flow).
  1. Let installer create runnable launcher entry:
  • The manager auto-creates .launch/<Game Name>.sh symlink when installer completes and .game exists.

Rename a Game Safely

  1. Rename .install/<Old>.sh to .install/<New>.sh.
  2. Rename .launch/<Old>.game to .launch/<New>.game.
  3. Rename .update/<Old>.sh if present.
  4. Remove stale .launch/<Old>.sh if still present.
  5. Re-run catalog audit and manual checks.

Remove a Game From Repo

  1. Delete .install/<Game>.sh.
  2. Delete .launch/<Game>.game.
  3. Delete .launch/<Game>.sh if tracked.
  4. Delete .update/<Game>.sh if present.
  5. Run catalog audit to confirm no orphan entries remain.

Disable Policy (Important)

When a request says "disable " without more detail:

  1. Default behavior: disable installs only.
  • Add #// to first line of .install/<Game Name>.sh.
  • Do not disable .launch/<Game Name>.game by default.
  • This preserves playability for users who already have the game installed.
  1. If user explicitly requests complete disable:
  • Add #// to first line of both:
    • .install/<Game Name>.sh
    • .launch/<Game Name>.game
  1. If wording is ambiguous but could imply full disable/removal:
  • Ask a short clarification question before changing launcher/removal behavior.

Manual Validation Checklist

  1. Run installer flow:
./linux-game-manager.sh -i
  1. Confirm launcher files exist:
ls ".launch/<Game Name>.game" ".launch/<Game Name>.sh"
  1. Run launcher flow:
./linux-game-manager.sh
  1. Run removal flow:
./linux-game-manager.sh -r
  1. If updater exists, run update flow:
./linux-game-manager.sh -u
  1. Run consistency audit:
python3 .codex/skills/linux-game-manager-dev/scripts/audit_game_catalog.py

Script Authoring Rules

  • Use camelCase variable names.
  • Use snake_case for function names.
  • Keep scripts robust when sourced in the manager shell.
  • Avoid introducing unnecessary colorized output.
  • For edited bash scripts, run shellcheck and fix all errors.
  • If shellcheck is not installed, prompt the user to install it first (see references/tooling-prereqs.md).

Pattern: uv + Host Python speechd Bindings

Use this pattern for Python games installed with uv when runtime speech support depends on import speechd.

  1. In installer script:
  • Check dependencies: git, uv, and host python binding import (python-speechd:speechd).
  • Clone game repository into ${installPath}/<GameRepoDir>.
  • Run uv sync in the project directory that contains pyproject.toml.
  • Resolve speechd source path from host Python via:
    • python3 -c 'import pathlib,speechd; print(pathlib.Path(speechd.__file__).resolve())'
  • Copy the module/package into a game-local directory such as:
    • ${installPath}/<GameRepoDir>/<RuntimePath>/.host-python/
  • Fail with a clear message if import or copy fails.
  1. In launcher script:
  • Export PYTHONPATH with the game-local .host-python directory prepended.
  • Launch via uv run ... from the same directory used for uv sync.
  1. Removal safety:
  • Ensure first installPath line in launcher points to a path that lets game_removal infer the game root correctly.
  • Do not put installPath in comments above that path line, because removal currently grabs the first matching line.