196 lines
8.0 KiB
Markdown
196 lines
8.0 KiB
Markdown
---
|
|
name: beatsaber-plugin-manager
|
|
description: Install or update a Beat Saber plugin in the plugin-helper repo by using the local helper workflow. Use when the user asks to add, install, update, bump, lock, bootstrap BSIPA, or manage a Beat Saber plugin release for a BSManager instance. Prefer upstream GitHub release artifacts for normal plugins; use BeatMods primarily as compatibility/dependency metadata, with CDN artifacts only for inaccessible upstream assets, BeatMods-only packages, or framework/library dependencies.
|
|
---
|
|
|
|
# Beat Saber Plugin Installer
|
|
|
|
Use the repository's own `plugin-helper` commands to manage plugins for BSManager instances whenever the helper supports the operation.
|
|
|
|
Before acting, read the shared policy references:
|
|
|
|
- [repo-workflow.md](../references/repo-workflow.md) for repo root, `.venv`, `PYTHONPATH=src`, dirty worktree handling, and validation commands.
|
|
- [state-and-profiles.md](../references/state-and-profiles.md) for `.state`, profiles, install identity, instance selection, and checkout locations.
|
|
- [artifact-policy.md](../references/artifact-policy.md) for GitHub/BeatMods/private-source/checksum/bootstrap policy.
|
|
- [live-validation.md](../references/live-validation.md) for smoke tests, logs, and process cleanup.
|
|
|
|
## Workflow
|
|
|
|
1. Confirm the workspace is the `plugin-helper` repo.
|
|
|
|
```bash
|
|
test -f pyproject.toml && test -d src/plugin_helper && test -d registry && test -d locks
|
|
```
|
|
|
|
2. Read the locked plugin entry and its registry file before changing them.
|
|
Open `src/plugin_helper` only when the command output disagrees with the
|
|
lock. `docs/SMOKETEST.md` is for the smoke after apply.
|
|
|
|
3. Determine the instance.
|
|
|
|
Prefer the instance the user names. If omitted, use the latest available
|
|
BSInstance unless the current task context clearly points at another
|
|
instance:
|
|
|
|
```bash
|
|
PYTHONPATH=src .venv/bin/python -m plugin_helper instances
|
|
```
|
|
|
|
4. Resolve the release source.
|
|
|
|
For BeatMods bootstrap or verified packages, query BeatMods with a browser-like user agent:
|
|
|
|
```bash
|
|
PYTHONPATH=src .venv/bin/python - <<'PY'
|
|
import json, urllib.request
|
|
from plugin_helper.beatmods import by_version_id, normalize_mods
|
|
|
|
game_version = "<instance>"
|
|
url = f"https://beatmods.com/api/mods?status=verified&gameVersion={game_version}&gameName=BeatSaber&platform=steampc"
|
|
req = urllib.request.Request(url, headers={"User-Agent": "Mozilla/5.0 plugin-helper"})
|
|
with urllib.request.urlopen(req, timeout=20) as response:
|
|
data = json.load(response)
|
|
mods = normalize_mods(data)
|
|
mods_by_version_id = by_version_id(mods)
|
|
print(json.dumps(
|
|
[
|
|
{
|
|
"name": mod.name,
|
|
"modId": mod.mod_id,
|
|
"gitUrl": mod.git_url,
|
|
"category": mod.category,
|
|
"versionId": mod.version_id,
|
|
"modVersion": mod.mod_version,
|
|
"zipHash": mod.zip_hash,
|
|
"dependencies": mod.dependencies,
|
|
"dependencyNames": [
|
|
mods_by_version_id[dep].name
|
|
for dep in mod.dependencies
|
|
if dep in mods_by_version_id
|
|
],
|
|
}
|
|
for mod in mods
|
|
],
|
|
indent=2,
|
|
)[:20000])
|
|
PY
|
|
```
|
|
|
|
Follow the artifact policy for GitHub-first sourcing, BeatMods exceptions,
|
|
and dependency closure. BeatMods CDN URLs are:
|
|
|
|
```text
|
|
https://beatmods.com/cdn/mod/<zipHash>.zip
|
|
```
|
|
|
|
For GitHub URLs, resolve the release from the user-provided repository or
|
|
release URL only.
|
|
|
|
Derive `<owner>/<repo>` and optional `<tag>` from the URL. Query the GitHub API directly for metadata:
|
|
|
|
```bash
|
|
curl -sS https://api.github.com/repos/<owner>/<repo>/releases
|
|
curl -sS https://api.github.com/repos/<owner>/<repo>/releases/tags/<tag>
|
|
```
|
|
|
|
Pick the asset that matches the Beat Saber instance/version. Prefer an exact versioned asset such as `1.40.8.zip` over broad or source archives. If multiple plausible assets remain, ask the user. When a release ships one zip per game version, record the asset name and the `gameVersion` string embedded in the DLL. A stale manifest is a warning on the chosen asset. It is not a reason to select a lower-named zip.
|
|
|
|
5. Inspect the asset before selecting an install strategy.
|
|
|
|
Download to the helper cache the planner searches:
|
|
|
|
```bash
|
|
mkdir -p .state/cache/downloads/<instance>/<plugin-id>
|
|
curl -L --fail -o .state/cache/downloads/<instance>/<plugin-id>/<asset-name> "<browser_download_url>"
|
|
sha256sum .state/cache/downloads/<instance>/<plugin-id>/<asset-name>
|
|
```
|
|
|
|
Match the checksum against GitHub's `digest` when available. Inspect zip contents:
|
|
|
|
```bash
|
|
unzip -l .state/cache/downloads/<instance>/<plugin-id>/<asset-name>
|
|
```
|
|
|
|
Use the install strategy guide in the artifact policy.
|
|
|
|
6. Update the registry and lockfile.
|
|
|
|
Add or update exactly one `[[plugins]]` entry in `registry/plugins.toml` with:
|
|
|
|
```toml
|
|
[[plugins]]
|
|
id = "<stable-plugin-id>"
|
|
name = "<human name>"
|
|
repo = "<owner>/<repo>"
|
|
asset_patterns = ["<asset-name-or-pattern>"]
|
|
install_strategy = "<strategy>"
|
|
category = "<category-if-obvious>"
|
|
```
|
|
|
|
Add or update the matching `[[plugins]]` entry in `locks/<instance>.lock.toml` with:
|
|
|
|
```toml
|
|
[[plugins]]
|
|
id = "<stable-plugin-id>"
|
|
repo = "<owner>/<repo>"
|
|
tag = "<tag>"
|
|
asset = "<asset-name>"
|
|
sha256 = "<asset-sha256>"
|
|
```
|
|
|
|
Preserve unrelated registry and lockfile content. Do not invent dependency versions unless they are explicitly stated by the provided release notes or existing local metadata.
|
|
|
|
7. Use the helper to validate, plan, and apply.
|
|
|
|
Pass `--state-dir .state` so the helper uses the repo-local download. On a
|
|
native Windows BSManager install, also pass
|
|
`--config plugin-helper.windows.toml.example --profile windows` when
|
|
`plugin-helper.local.toml` is absent. `--state-dir .state` alone selects the
|
|
`default` install id, which is a different bootstrap record from the
|
|
`windows` profile.
|
|
|
|
```bash
|
|
PYTHONPATH=src .venv/bin/python -m plugin_helper --config plugin-helper.windows.toml.example --profile windows --state-dir .state check --instance <instance>
|
|
PYTHONPATH=src .venv/bin/python -m plugin_helper --config plugin-helper.windows.toml.example --profile windows --state-dir .state plan --instance <instance> --plugin <plugin-id>
|
|
PYTHONPATH=src .venv/bin/python -m plugin_helper --config plugin-helper.windows.toml.example --profile windows --state-dir .state apply <generated-plan-path>
|
|
```
|
|
|
|
`plan` keeps the dependency closure in `unchanged` when those live files
|
|
already match. `changes` is what `apply` writes. Confirm `Changes:` is the
|
|
intended plugin before applying.
|
|
|
|
8. Verify the result.
|
|
|
|
Confirm the installed file hashes match the plan or archive members:
|
|
|
|
```bash
|
|
PYTHONPATH=src .venv/bin/python -m plugin_helper --state-dir .state state --instance <instance>
|
|
PYTHONPATH=src .venv/bin/python -m plugin_helper --state-dir .state check --instance <instance>
|
|
PYTHONPATH=src .venv/bin/python -m compileall -q src tests
|
|
PYTHONPATH=src .venv/bin/python -m unittest discover -s tests
|
|
```
|
|
|
|
For live Beat Saber validation, follow the live-validation reference. Also
|
|
record when a BeatMods CDN artifact was used so it can be migrated to
|
|
upstream GitHub later if possible.
|
|
|
|
9. Final response.
|
|
|
|
Include:
|
|
|
|
- release URL/tag/asset used
|
|
- files changed in the repo and helper state
|
|
- live instance files changed
|
|
- backup path created by the helper
|
|
- validation commands and results
|
|
|
|
## Mistake Recovery
|
|
|
|
If you installed from the wrong release or repo during the current task:
|
|
|
|
1. Restore affected live files from the helper backup created by that mistaken apply.
|
|
2. Remove mistaken downloaded assets and mistaken plan files from `.state`.
|
|
3. Correct the registry and lockfile to the user-provided release URL.
|
|
4. Rerun `check`, `plan`, and `apply` with `--state-dir .state`.
|
|
5. Keep or report only the backup relevant to the final correct apply unless the user asks for full audit history.
|