Codex skill for development added. Tested by using it to set up Play Palace.
This commit is contained in:
81
.codex/skills/linux-game-manager-dev/SKILL.md
Normal file
81
.codex/skills/linux-game-manager-dev/SKILL.md
Normal file
@@ -0,0 +1,81 @@
|
||||
---
|
||||
name: linux-game-manager-dev
|
||||
description: Develop and maintain Linux Game Manager in this repository. Use when adding or removing games, editing `.install`/`.launch`/`.update` scripts, changing `linux-game-manager.sh` installer/launcher/removal/update/CLI behavior, validating accessibility-sensitive flows, or refreshing project-local skill docs after functionality changes.
|
||||
---
|
||||
|
||||
# Linux Game Manager Development
|
||||
|
||||
Use this skill to make safe, consistent changes to Linux Game Manager and keep the skill accurate as the codebase evolves.
|
||||
|
||||
## Fast Routing
|
||||
|
||||
1. If the task adds/removes/changes a game, read `references/game-extension.md`.
|
||||
2. If the task changes orchestration/CLI/config behavior, read `references/core-map.md`.
|
||||
3. If the task changes behavior and you are updating this skill, read `references/skill-maintenance.md`.
|
||||
4. Run `python3 .codex/skills/linux-game-manager-dev/scripts/audit_game_catalog.py` before and after major game-catalog changes.
|
||||
|
||||
## Core Workflow
|
||||
|
||||
1. Inspect relevant behavior and identify affected surfaces (`.install`, `.launch`, `.update`, `linux-game-manager.sh`, `speech`, docs).
|
||||
2. Implement with existing patterns and helper functions instead of inventing new flows.
|
||||
3. Validate runtime behavior with CLI/manual checks:
|
||||
- `./linux-game-manager.sh -i`
|
||||
- `./linux-game-manager.sh -r`
|
||||
- `./linux-game-manager.sh -u`
|
||||
- `./linux-game-manager.sh -t`
|
||||
4. Validate catalog consistency:
|
||||
- `python3 .codex/skills/linux-game-manager-dev/scripts/audit_game_catalog.py`
|
||||
5. If bash files were edited:
|
||||
- Verify `shellcheck` is installed.
|
||||
- If missing, stop and prompt the user to install it (see `references/tooling-prereqs.md`).
|
||||
- Run shellcheck on edited files and fix all reported errors.
|
||||
6. If functionality changed, refresh this skill using `references/skill-maintenance.md`.
|
||||
|
||||
## Non-Negotiable Rules
|
||||
|
||||
1. Keep installer and launcher base filenames identical:
|
||||
- `.install/<Game Name>.sh`
|
||||
- `.launch/<Game Name>.game`
|
||||
2. Ensure launcher scripts include a concrete `installPath`-based path so removal can locate game data.
|
||||
3. Define `run_update()` in any `.update/<Game>.sh` script.
|
||||
4. Preserve accessibility-first interaction:
|
||||
- Keep dialog/yad wrapper usage (`ui_*` helpers) consistent.
|
||||
- Do not introduce keyboard traps.
|
||||
- For GUI applications, do not add new `speech-dispatcher`/`spd-say` dependencies.
|
||||
5. Keep new script variables camelCase, function names snake_case, class names PascalCase.
|
||||
6. For ambiguous "disable game" requests, default to disabling installer visibility only and preserve launcher playability unless the user explicitly requests complete disable.
|
||||
|
||||
## Required Validation
|
||||
|
||||
1. Run catalog audit:
|
||||
- `python3 .codex/skills/linux-game-manager-dev/scripts/audit_game_catalog.py`
|
||||
2. Run manual command checks relevant to change scope:
|
||||
- install flow: `./linux-game-manager.sh -i`
|
||||
- launcher flow: `./linux-game-manager.sh`
|
||||
- removal flow: `./linux-game-manager.sh -r`
|
||||
- update flow: `./linux-game-manager.sh -u`
|
||||
3. Run shellcheck on every edited bash script and fix all issues.
|
||||
- If shellcheck is unavailable, prompt the user to install it before continuing.
|
||||
4. Validate this skill structure after edits:
|
||||
- `python3 /home/storm/.codex/skills/.system/skill-creator/scripts/quick_validate.py .codex/skills/linux-game-manager-dev`
|
||||
|
||||
## Mandatory Skill Maintenance
|
||||
|
||||
Treat this skill as stale immediately after any change to:
|
||||
- `linux-game-manager.sh`
|
||||
- Any file in `.install/`, `.launch/`, `.update/`, or `speech/`
|
||||
- `README.md`
|
||||
- Any change to game lifecycle expectations (install path rules, update hooks, CLI options, helper function contracts)
|
||||
|
||||
When stale, perform the full refresh workflow in `references/skill-maintenance.md` before completing the task.
|
||||
|
||||
## References
|
||||
|
||||
- `references/core-map.md`: Architecture and extension map.
|
||||
- `references/game-extension.md`: Exact workflow for adding/removing/extending games.
|
||||
- `references/skill-maintenance.md`: Critical instructions to keep this skill accurate after code changes.
|
||||
- `references/tooling-prereqs.md`: Required tools and shellcheck installation prompts by distro.
|
||||
|
||||
## Scripts
|
||||
|
||||
- `scripts/audit_game_catalog.py`: Reports installer/launcher/update consistency and disabled entries.
|
||||
4
.codex/skills/linux-game-manager-dev/agents/openai.yaml
Normal file
4
.codex/skills/linux-game-manager-dev/agents/openai.yaml
Normal file
@@ -0,0 +1,4 @@
|
||||
interface:
|
||||
display_name: "Linux Game Manager Dev"
|
||||
short_description: "Add games and extend linux-game-manager safely"
|
||||
default_prompt: "Use the project workflows to add games, modify manager behavior, validate accessibility-friendly flows, and keep this skill synchronized with code changes."
|
||||
76
.codex/skills/linux-game-manager-dev/references/core-map.md
Normal file
76
.codex/skills/linux-game-manager-dev/references/core-map.md
Normal file
@@ -0,0 +1,76 @@
|
||||
# Linux Game Manager Core Map
|
||||
|
||||
Last refreshed: 2026-02-21
|
||||
|
||||
## Top-Level Structure
|
||||
|
||||
- `linux-game-manager.sh`: Main orchestrator, UI wrappers, CLI option handling, install/remove/update flows, cache and settings behavior.
|
||||
- `.install/`: Per-game installer scripts sourced by `game_installer`.
|
||||
- `.launch/`: Per-game launch scripts (`.game`) and runnable entries (`.sh`, usually symlinks).
|
||||
- `.update/`: Optional per-game update scripts expected to define `run_update()`.
|
||||
- `speech/speak_window_title.sh`: Accessibility helper for announcing focused window titles.
|
||||
- `README.md`: Project summary and high-level behavior notes.
|
||||
- `.files/`: Game-specific auxiliary assets/scripts used by some installers or launchers.
|
||||
|
||||
## Catalog Snapshot
|
||||
|
||||
- Installers: 38 (`.install/*.sh`)
|
||||
- Launcher definitions: 38 (`.launch/*.game`)
|
||||
- Launcher runnable entries: 26 (`.launch/*.sh`, both symlinks and files)
|
||||
- Update scripts: 5 (`.update/*.sh`)
|
||||
|
||||
Regenerate this snapshot with:
|
||||
|
||||
```bash
|
||||
python3 .codex/skills/linux-game-manager-dev/scripts/audit_game_catalog.py
|
||||
```
|
||||
|
||||
## Main Runtime Flows
|
||||
|
||||
1. **Install flow**
|
||||
- `game_installer` builds menu from `.install/*.sh`.
|
||||
- Selected installer is sourced in the current shell.
|
||||
- If `.launch/<game>.game` exists and `.launch/<game>.sh` does not, the manager creates a symlink.
|
||||
|
||||
2. **Launch flow**
|
||||
- `game_launcher` enumerates `.launch/*.sh` entries.
|
||||
- Entries with first line `#//` are skipped.
|
||||
- Selected launcher is sourced/executed.
|
||||
|
||||
3. **Removal flow**
|
||||
- `game_removal` resolves launcher entry to real script.
|
||||
- It extracts the first `installPath`-containing line from launcher script to infer directory to remove.
|
||||
- If no `installPath` reference is found, only launcher entry is removed.
|
||||
|
||||
4. **Update flow**
|
||||
- `game_update` lists `.update/*.sh`.
|
||||
- Selected updater is sourced.
|
||||
- `run_update()` is called and must exist.
|
||||
|
||||
## CLI Surface
|
||||
|
||||
- `-i`: install game
|
||||
- `-r`: remove game
|
||||
- `-u`: update game
|
||||
- `-t`: show number of available games
|
||||
- `-C`: clear cache
|
||||
- `-D`: create desktop launcher
|
||||
- `-L`: show license
|
||||
- `-h`: show help
|
||||
- `-N`: enable no-cache mode
|
||||
- `-R`: force redownload mode
|
||||
|
||||
## Config and State
|
||||
|
||||
- Cache: `${XDG_CACHE_HOME:-$HOME/.cache}/linux-game-manager`
|
||||
- Config base: `${XDG_CONFIG_HOME:-$HOME/.config}/storm-games/linux-game-manager`
|
||||
- Settings overrides: `settings.conf` in config base
|
||||
- Default install root: `${HOME}/.local/games`
|
||||
|
||||
## Contributor Pitfalls
|
||||
|
||||
- Mismatched `.install/<Game>.sh` vs `.launch/<Game>.game` names create orphaned or invisible entries.
|
||||
- Missing `installPath` reference in launcher prevents full uninstall.
|
||||
- Missing `run_update()` in `.update` scripts breaks update flow.
|
||||
- Bypassing shared download helpers risks cache and validation regressions.
|
||||
- For `uv`-based Python games that use `accessible-output2`, include a host copy of `libspeechd.so.2` and export `LD_LIBRARY_PATH` from the launcher to avoid distro packaging differences.
|
||||
@@ -0,0 +1,134 @@
|
||||
# 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}`.
|
||||
|
||||
2. 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:
|
||||
|
||||
```bash
|
||||
gamePath="${installPath}/MyGame"
|
||||
```
|
||||
|
||||
- Run the game from that path.
|
||||
|
||||
3. Optional update script:
|
||||
- Path: `.update/<Game Name>.sh`
|
||||
- Implement `run_update()` (required by update flow).
|
||||
|
||||
4. 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 <game>" 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.
|
||||
|
||||
2. If user explicitly requests complete disable:
|
||||
- Add `#//` to first line of both:
|
||||
- `.install/<Game Name>.sh`
|
||||
- `.launch/<Game Name>.game`
|
||||
|
||||
3. 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:
|
||||
|
||||
```bash
|
||||
./linux-game-manager.sh -i
|
||||
```
|
||||
|
||||
2. Confirm launcher files exist:
|
||||
|
||||
```bash
|
||||
ls ".launch/<Game Name>.game" ".launch/<Game Name>.sh"
|
||||
```
|
||||
|
||||
3. Run launcher flow:
|
||||
|
||||
```bash
|
||||
./linux-game-manager.sh
|
||||
```
|
||||
|
||||
4. Run removal flow:
|
||||
|
||||
```bash
|
||||
./linux-game-manager.sh -r
|
||||
```
|
||||
|
||||
5. If updater exists, run update flow:
|
||||
|
||||
```bash
|
||||
./linux-game-manager.sh -u
|
||||
```
|
||||
|
||||
6. Run consistency audit:
|
||||
|
||||
```bash
|
||||
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 + Speech Dispatcher Host Libraries
|
||||
|
||||
Use this pattern for Python games installed with `uv` when runtime speech support depends on system `libspeechd`.
|
||||
|
||||
1. In installer script:
|
||||
- Check dependencies: `git` and `uv`.
|
||||
- Clone game repository into `${installPath}/<GameRepoDir>`.
|
||||
- Run `uv sync` in the project directory that contains `pyproject.toml`.
|
||||
- Locate `libspeechd.so.2` from host system using:
|
||||
- `ldconfig -p` when available.
|
||||
- Fallback paths for common distros:
|
||||
- `/usr/lib/libspeechd.so.2` (Arch-style)
|
||||
- `/usr/lib/x86_64-linux-gnu/libspeechd.so.2` (Debian/Ubuntu-style)
|
||||
- `/usr/lib64/libspeechd.so.2` and related `/lib*` fallbacks
|
||||
- Copy resolved library into a game-local directory such as:
|
||||
- `${installPath}/<GameRepoDir>/<RuntimePath>/.host-libs/libspeechd.so.2`
|
||||
- Fail with a clear message if library is not found.
|
||||
|
||||
2. In launcher script:
|
||||
- Export `LD_LIBRARY_PATH` with the game-local `.host-libs` directory prepended.
|
||||
- Launch via `uv run ...` from the same directory used for `uv sync`.
|
||||
|
||||
3. Removal safety:
|
||||
- Ensure first `installPath` line in launcher points to a path that lets `game_removal` infer the game root correctly.
|
||||
@@ -0,0 +1,53 @@
|
||||
# Skill Maintenance (Critical)
|
||||
|
||||
This skill is only trustworthy if it is refreshed immediately after behavior changes.
|
||||
|
||||
## Mandatory Refresh Triggers
|
||||
|
||||
Run this maintenance workflow whenever any of these change:
|
||||
|
||||
- `linux-game-manager.sh`
|
||||
- Anything in `.install/`
|
||||
- Anything in `.launch/`
|
||||
- Anything in `.update/`
|
||||
- Anything in `speech/`
|
||||
- `README.md`
|
||||
- Any game lifecycle contract (install path usage, symlink behavior, update function contracts, CLI flags)
|
||||
|
||||
## Refresh Workflow
|
||||
|
||||
1. Run catalog audit and capture output:
|
||||
|
||||
```bash
|
||||
python3 .codex/skills/linux-game-manager-dev/scripts/audit_game_catalog.py
|
||||
```
|
||||
|
||||
2. Re-check core flow definitions in `linux-game-manager.sh`:
|
||||
|
||||
```bash
|
||||
rg -n "game_installer|game_launcher|game_removal|game_update|getopts|help\\(" linux-game-manager.sh
|
||||
```
|
||||
|
||||
3. Update skill references:
|
||||
- Update `references/core-map.md` catalog snapshot if counts changed.
|
||||
- Update `references/core-map.md` flow descriptions if behavior changed.
|
||||
- Update `references/game-extension.md` if onboarding or naming rules changed.
|
||||
- Update this file if refresh triggers or process changed.
|
||||
|
||||
4. Validate the skill structure:
|
||||
|
||||
```bash
|
||||
python3 /home/storm/.codex/skills/.system/skill-creator/scripts/quick_validate.py .codex/skills/linux-game-manager-dev
|
||||
```
|
||||
|
||||
5. If any bash scripts changed, run shellcheck on edited files and fix all errors.
|
||||
- If `shellcheck` is missing, pause and prompt the user to install it using `references/tooling-prereqs.md`.
|
||||
|
||||
## Completion Criteria
|
||||
|
||||
Do not consider maintenance complete until all are true:
|
||||
|
||||
1. Catalog audit shows no critical mismatches, and any warnings are reviewed.
|
||||
2. All changed behavior is reflected in skill reference files.
|
||||
3. Skill passes `quick_validate.py`.
|
||||
4. Any edited bash scripts are shellcheck-clean.
|
||||
@@ -0,0 +1,38 @@
|
||||
# Tooling Prerequisites
|
||||
|
||||
## Required Tool for Bash Changes
|
||||
|
||||
- `shellcheck` is mandatory whenever editing any bash/sh file in this repository.
|
||||
- If `shellcheck` is not available, prompt the user to install it before continuing validation.
|
||||
|
||||
Check availability:
|
||||
|
||||
```bash
|
||||
command -v shellcheck
|
||||
```
|
||||
|
||||
## Prompt Template
|
||||
|
||||
Use this exact style when missing:
|
||||
|
||||
`shellcheck is required for bash/sh edits in linux-game-manager. Please install it, then I will continue validation.`
|
||||
|
||||
## Install Commands by Common Distro Family
|
||||
|
||||
- Arch/Manjaro:
|
||||
- `sudo pacman -S shellcheck`
|
||||
- Debian/Ubuntu/Linux Mint/Pop!_OS:
|
||||
- `sudo apt update && sudo apt install -y shellcheck`
|
||||
- Fedora/RHEL/CentOS Stream:
|
||||
- `sudo dnf install -y ShellCheck`
|
||||
- openSUSE:
|
||||
- `sudo zypper install -y ShellCheck`
|
||||
- Alpine:
|
||||
- `sudo apk add shellcheck`
|
||||
|
||||
If distro is unknown, ask the user what distribution they are on and provide the matching package command.
|
||||
|
||||
## Notes for LGM Collaboration
|
||||
|
||||
- Do not skip shellcheck for “small” bash changes.
|
||||
- Fix all shellcheck errors; warnings may be suppressed only when required by sourced-global patterns and with a short comment.
|
||||
@@ -0,0 +1,202 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Audit Linux Game Manager catalog consistency."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def read_first_line(file_path: Path) -> str:
|
||||
try:
|
||||
with file_path.open("r", encoding="utf-8") as handle:
|
||||
return handle.readline().strip()
|
||||
except OSError:
|
||||
return ""
|
||||
|
||||
|
||||
def has_run_update(file_path: Path) -> bool:
|
||||
try:
|
||||
content = file_path.read_text(encoding="utf-8")
|
||||
except OSError:
|
||||
return False
|
||||
|
||||
return "run_update()" in content or "run_update ()" in content
|
||||
|
||||
|
||||
def collect_names(file_paths: list[Path], suffix: str) -> list[str]:
|
||||
return sorted(file_path.name[: -len(suffix)] for file_path in file_paths)
|
||||
|
||||
|
||||
def count_disabled(file_paths: list[Path]) -> list[str]:
|
||||
disabledNames = []
|
||||
for file_path in file_paths:
|
||||
if read_first_line(file_path).startswith("#//"):
|
||||
disabledNames.append(file_path.name)
|
||||
return sorted(disabledNames)
|
||||
|
||||
|
||||
def build_report(repo_root: Path) -> dict:
|
||||
installDir = repo_root / ".install"
|
||||
launchDir = repo_root / ".launch"
|
||||
updateDir = repo_root / ".update"
|
||||
|
||||
missingDirs = [
|
||||
str(path.relative_to(repo_root))
|
||||
for path in [installDir, launchDir, updateDir]
|
||||
if not path.exists()
|
||||
]
|
||||
if missingDirs:
|
||||
raise FileNotFoundError(
|
||||
f"Expected directories not found: {', '.join(missingDirs)}"
|
||||
)
|
||||
|
||||
installPaths = sorted(installDir.glob("*.sh"))
|
||||
launchGamePaths = sorted(launchDir.glob("*.game"))
|
||||
launchShPaths = sorted(launchDir.glob("*.sh"))
|
||||
updatePaths = sorted(updateDir.glob("*.sh"))
|
||||
|
||||
installerNames = collect_names(installPaths, ".sh")
|
||||
launcherGameNames = collect_names(launchGamePaths, ".game")
|
||||
launcherShNames = collect_names(launchShPaths, ".sh")
|
||||
|
||||
launcherSymlinkCount = sum(1 for path in launchShPaths if path.is_symlink())
|
||||
launcherFileCount = len(launchShPaths) - launcherSymlinkCount
|
||||
|
||||
missingLauncherGameForInstaller = sorted(
|
||||
set(installerNames) - set(launcherGameNames)
|
||||
)
|
||||
missingInstallerForLauncherGame = sorted(
|
||||
set(launcherGameNames) - set(installerNames)
|
||||
)
|
||||
missingLauncherShForLauncherGame = sorted(
|
||||
set(launcherGameNames) - set(launcherShNames)
|
||||
)
|
||||
orphanLauncherSh = sorted(set(launcherShNames) - set(launcherGameNames))
|
||||
|
||||
updateWithoutRunFunction = sorted(
|
||||
path.name for path in updatePaths if not has_run_update(path)
|
||||
)
|
||||
|
||||
report = {
|
||||
"repoRoot": str(repo_root),
|
||||
"criticalMismatches": [
|
||||
"missingLauncherGameForInstaller",
|
||||
"updateScriptsMissingRunUpdate",
|
||||
],
|
||||
"warningMismatches": [
|
||||
"missingInstallerForLauncherGame",
|
||||
"missingLauncherShForLauncherGame",
|
||||
"orphanLauncherSh",
|
||||
],
|
||||
"counts": {
|
||||
"installers": len(installPaths),
|
||||
"launcherGameDefinitions": len(launchGamePaths),
|
||||
"launcherRunnableEntries": len(launchShPaths),
|
||||
"launcherRunnableSymlinks": launcherSymlinkCount,
|
||||
"launcherRunnableRegularFiles": launcherFileCount,
|
||||
"updateScripts": len(updatePaths),
|
||||
},
|
||||
"disabledEntries": {
|
||||
"installers": count_disabled(installPaths),
|
||||
"launchers": count_disabled(launchShPaths),
|
||||
},
|
||||
"mismatches": {
|
||||
"missingLauncherGameForInstaller": missingLauncherGameForInstaller,
|
||||
"missingInstallerForLauncherGame": missingInstallerForLauncherGame,
|
||||
"missingLauncherShForLauncherGame": missingLauncherShForLauncherGame,
|
||||
"orphanLauncherSh": orphanLauncherSh,
|
||||
"updateScriptsMissingRunUpdate": updateWithoutRunFunction,
|
||||
},
|
||||
}
|
||||
return report
|
||||
|
||||
|
||||
def print_human_report(report: dict) -> None:
|
||||
counts = report["counts"]
|
||||
mismatches = report["mismatches"]
|
||||
criticalMismatches = report["criticalMismatches"]
|
||||
warningMismatches = report["warningMismatches"]
|
||||
disabledEntries = report["disabledEntries"]
|
||||
|
||||
print(f"Repository: {report['repoRoot']}")
|
||||
print("Counts:")
|
||||
print(f" Installers: {counts['installers']}")
|
||||
print(f" Launcher .game files: {counts['launcherGameDefinitions']}")
|
||||
print(f" Launcher .sh entries: {counts['launcherRunnableEntries']}")
|
||||
print(f" Symlinks: {counts['launcherRunnableSymlinks']}")
|
||||
print(f" Regular files: {counts['launcherRunnableRegularFiles']}")
|
||||
print(f" Update scripts: {counts['updateScripts']}")
|
||||
|
||||
print("Disabled entries:")
|
||||
print(f" Installers: {len(disabledEntries['installers'])}")
|
||||
if disabledEntries["installers"]:
|
||||
print(" " + ", ".join(disabledEntries["installers"]))
|
||||
print(f" Launchers: {len(disabledEntries['launchers'])}")
|
||||
if disabledEntries["launchers"]:
|
||||
print(" " + ", ".join(disabledEntries["launchers"]))
|
||||
|
||||
print("Critical checks:")
|
||||
for key in criticalMismatches:
|
||||
values = mismatches[key]
|
||||
print(f" {key}: {len(values)}")
|
||||
if values:
|
||||
print(" " + ", ".join(values))
|
||||
|
||||
print("Warnings:")
|
||||
for key in warningMismatches:
|
||||
values = mismatches[key]
|
||||
print(f" {key}: {len(values)}")
|
||||
if values:
|
||||
print(" " + ", ".join(values))
|
||||
|
||||
criticalTotal = sum(len(mismatches[key]) for key in criticalMismatches)
|
||||
if criticalTotal == 0:
|
||||
print("Result: OK (no critical mismatches)")
|
||||
else:
|
||||
print("Result: ATTENTION REQUIRED (critical mismatches detected)")
|
||||
|
||||
|
||||
def parse_args() -> argparse.Namespace:
|
||||
defaultRepoRoot = Path(__file__).resolve().parents[4]
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Audit installer/launcher/update consistency for linux-game-manager."
|
||||
)
|
||||
parser.add_argument(
|
||||
"--repo-root",
|
||||
default=str(defaultRepoRoot),
|
||||
help=f"Repository root path (default: {defaultRepoRoot})",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--json",
|
||||
action="store_true",
|
||||
help="Emit JSON instead of human-readable text",
|
||||
)
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
def main() -> int:
|
||||
args = parse_args()
|
||||
repoRoot = Path(args.repo_root).resolve()
|
||||
|
||||
try:
|
||||
report = build_report(repoRoot)
|
||||
except FileNotFoundError as error:
|
||||
print(str(error), file=sys.stderr)
|
||||
return 2
|
||||
|
||||
if args.json:
|
||||
print(json.dumps(report, indent=2, sort_keys=True))
|
||||
else:
|
||||
print_human_report(report)
|
||||
|
||||
criticalTotal = sum(
|
||||
len(report["mismatches"][bucket]) for bucket in report["criticalMismatches"]
|
||||
)
|
||||
return 1 if criticalTotal else 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
69
.install/Play Palace.sh
Normal file
69
.install/Play Palace.sh
Normal file
@@ -0,0 +1,69 @@
|
||||
check_dependencies git uv
|
||||
|
||||
# shellcheck disable=SC2154 # installPath is exported by linux-game-manager.sh
|
||||
gameRoot="${installPath}/PlayPalace11"
|
||||
desktopPath="${gameRoot}/clients/desktop"
|
||||
hostLibDir="${desktopPath}/.host-libs"
|
||||
speechdLibPath=""
|
||||
libCandidates=(
|
||||
"/usr/lib/libspeechd.so.2"
|
||||
"/usr/lib64/libspeechd.so.2"
|
||||
"/usr/lib/x86_64-linux-gnu/libspeechd.so.2"
|
||||
"/lib/x86_64-linux-gnu/libspeechd.so.2"
|
||||
"/lib64/libspeechd.so.2"
|
||||
)
|
||||
|
||||
if [[ -e "${gameRoot}" ]]; then
|
||||
ui_msgbox "Game Installer" "Game Installer" "\"${gameRoot}\" already exists. Remove it first or choose a different game."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mkdir -p "${installPath}" || {
|
||||
ui_msgbox "Game Installer" "Game Installer" "Could not create ${installPath}."
|
||||
exit 1
|
||||
}
|
||||
|
||||
if ! git -C "${installPath}" clone "https://github.com/XGDevGroup/PlayPalace11.git"; then
|
||||
ui_msgbox "Game Installer" "Game Installer" "Could not clone Play Palace from GitHub."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! pushd "${desktopPath}" > /dev/null; then
|
||||
ui_msgbox "Game Installer" "Game Installer" "Could not find desktop client path at ${desktopPath}."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! uv sync; then
|
||||
popd > /dev/null || exit 1
|
||||
ui_msgbox "Game Installer" "Game Installer" "uv sync failed for Play Palace."
|
||||
exit 1
|
||||
fi
|
||||
popd > /dev/null || exit 1
|
||||
|
||||
if command -v ldconfig > /dev/null 2>&1; then
|
||||
speechdLibPath="$(ldconfig -p 2> /dev/null | awk '/libspeechd\.so\.2/{print $NF; exit}')"
|
||||
fi
|
||||
|
||||
if [[ -z "${speechdLibPath}" ]]; then
|
||||
for libPath in "${libCandidates[@]}"; do
|
||||
if [[ -r "${libPath}" ]]; then
|
||||
speechdLibPath="${libPath}"
|
||||
break
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
if [[ -z "${speechdLibPath}" ]]; then
|
||||
ui_msgbox "Game Installer" "Game Installer" "Could not find libspeechd.so.2.\nInstall speech-dispatcher (Arch) or a libspeechd package (Debian/Ubuntu) and try again."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mkdir -p "${hostLibDir}" || {
|
||||
ui_msgbox "Game Installer" "Game Installer" "Could not create ${hostLibDir}."
|
||||
exit 1
|
||||
}
|
||||
|
||||
if ! cp -Lf "${speechdLibPath}" "${hostLibDir}/libspeechd.so.2"; then
|
||||
ui_msgbox "Game Installer" "Game Installer" "Could not copy ${speechdLibPath} into ${hostLibDir}."
|
||||
exit 1
|
||||
fi
|
||||
18
.launch/Play Palace.game
Normal file
18
.launch/Play Palace.game
Normal file
@@ -0,0 +1,18 @@
|
||||
check_dependencies uv
|
||||
|
||||
# shellcheck disable=SC2154 # installPath is exported by linux-game-manager.sh
|
||||
gamePath="${installPath}/PlayPalace11/clients"
|
||||
desktopPath="${gamePath}/desktop"
|
||||
hostLibDir="${desktopPath}/.host-libs"
|
||||
|
||||
if ! [[ -d "${desktopPath}" ]]; then
|
||||
ui_msgbox "Linux Game Manager" "Linux Game Manager" "Play Palace is not installed at ${desktopPath}."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -d "${hostLibDir}" ]]; then
|
||||
export LD_LIBRARY_PATH="${hostLibDir}${LD_LIBRARY_PATH:+:${LD_LIBRARY_PATH}}"
|
||||
fi
|
||||
|
||||
pushd "${desktopPath}" || exit 1
|
||||
uv run python client.py
|
||||
Reference in New Issue
Block a user