Files
plugin-helper/.agents/skills/beatsaber-plugin-builder/SKILL.md
T
2026-07-10 08:42:55 -07:00

134 lines
6.4 KiB
Markdown

---
name: beatsaber-plugin-builder
description: Build, test-compile, or package Beat Saber PC BSIPA plugin source on Linux from local checkouts, GitHub branches, or pull requests. Use when asked to build a Beat Saber plugin, compile a plugin PR, produce a DLL/zip artifact, configure BeatSaberDir/local refs for dotnet builds, or diagnose Linux build failures for .NET Framework BSIPA projects.
---
# Beat Saber Plugin Builder
Use this skill to compile PC BSIPA plugin projects on this Linux host, especially from the `plugin-helper` repo. The workflow is adapted from the Setlist repo's Linux/Cursor build notes.
Before building, 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) when handing a built artifact to `plugin-helper`.
- [live-validation.md](../references/live-validation.md) when validating a built plugin in-game.
For detailed Linux/BSMT behavior, read [linux-bsipa-build.md](references/linux-bsipa-build.md) when you need to configure a project, fix missing references, package artifacts, or explain a failure.
## Core Workflow
1. Confirm context.
```bash
pwd
git status --short
sed -n '1,220p' plugin-helper.local.toml
```
In `plugin-helper`, run commands from repo root. Treat shared profile and
dirty-worktree policy as binding.
2. Resolve source.
For a GitHub PR, clone or reuse a checkout according to the shared source
checkout policy, add/fetch the upstream remote if needed, and check out the
PR head:
```bash
git clone https://github.com/<owner>/<repo>.git <state_dir>/build/<name>
git -C <state_dir>/build/<name> fetch origin pull/<pr>/head:pr-<pr>
git -C <state_dir>/build/<name> checkout pr-<pr>
```
If the PR is from a fork and the repo already has a fork remote, preserve it.
Never overwrite local source changes without explicit approval.
3. Inspect build shape.
```bash
find <checkout> -maxdepth 3 -name '*.sln' -o -name '*.csproj' -o -name 'manifest.json' -o -name 'Directory.Build.props'
sed -n '1,240p' <project>.csproj
```
Note target framework, `BeatSaberDir`, `LocalRefsDir`, package references, and whether `DisableCopyToPlugins` is already set.
4. Choose Beat Saber references.
Prefer a BSManager instance matching the plugin or manifest `gameVersion`.
If the user did not specify an instance and the plugin does not require a
narrower version, use the latest available BSInstance. Read
`plugin-helper.local.toml` and select the intended profile, then use that
profile's `instances_root` and matching `state_dir` instead of searching
default BSManager paths manually:
```bash
PYTHONPATH=src .venv/bin/python -m plugin_helper --profile <profile-id> instances
```
Use a local `.csproj.user` or MSBuild properties rather than committing
machine paths. For test builds, pass `-p:DisableCopyToPlugins=True` and, for
BSMT projects that expose it, `-p:DisableCopyToGame=True` so compilation
does not mutate the game install.
5. Restore and build.
Prefer the solution when present; otherwise build the plugin `.csproj`:
```bash
dotnet restore <solution-or-project>
dotnet build <solution-or-project> -c Release -p:DisableCopyToPlugins=True -p:DisableCopyToGame=True
```
If the project lacks .NET Framework reference assemblies on Linux, add or
pass the package matching the project's target framework, usually
`Microsoft.NETFramework.ReferenceAssemblies.net48` for current BSIPA
projects, as described in the reference file.
6. Verify Beat Saber API changes before patching gameplay code.
When a Beat Saber upgrade breaks a type/member reference, first determine
whether the API moved assemblies before substituting another type. Inspect
the target game DLLs and nearby mod sources:
```bash
strings "<BeatSaberDir>/Beat Saber_Data/Managed/Main.dll" | rg 'TypeOrMemberName'
strings "<BeatSaberDir>/Beat Saber_Data/Managed/HMLib.dll" | rg 'TypeOrMemberName'
ilspycmd -t TypeName "<BeatSaberDir>/Beat Saber_Data/Managed/Main.dll" | sed -n '1,220p'
rg -n 'TypeOrMemberName|NearbyConcept' ~/src/<owner>/<repo> ~/src/Auros/SiraUtil ~/src/nike4613/BeatSaber-IPA-Reloaded
```
7. Collect artifacts.
Find produced DLLs and release zips:
```bash
find <checkout> -path '*/bin/*' \( -name '*.dll' -o -name '*.zip' \) -print
```
Verify the DLL name, version, and manifest. If the result is meant for
`plugin-helper`, place a copy under
`<state_dir>/instances/<instance>/downloads/<plugin-id>/` for the selected
profile and use the helper plan/apply workflow rather than hand-copying into
a BSManager instance.
8. Validate.
For skill edits inside this repo, run the shared skill validation plus:
```bash
python /home/pleb/.codex/skills/.system/skill-creator/scripts/quick_validate.py .agents/skills/beatsaber-plugin-builder
PYTHONPATH=src .venv/bin/python -m compileall -q src tests
PYTHONPATH=src .venv/bin/python -m unittest discover -s tests
```
For a plugin build, at minimum report the exact `dotnet build` result and artifact paths. For live game validation, use `docs/SMOKETEST.md` and tear down Beat Saber processes afterward.
## Failure Triage
- Missing `Microsoft.NETFramework.ReferenceAssemblies`: add the package matching the target framework, usually `Microsoft.NETFramework.ReferenceAssemblies.net48` for current projects, or pass an equivalent MSBuild/package restore fix.
- Missing `Main.dll`, `HMUI.dll`, `IPA.Loader.dll`, `BSML.dll`, `SongCore.dll`, or similar: `BeatSaberDir` points at the wrong/unmodded instance, or dependencies are absent from `Plugins/`/`Libs/`.
- BSMT copies to `IPA/Pending` or `Plugins` during build: rebuild with `-p:DisableCopyToPlugins=True -p:DisableCopyToGame=True` unless the user explicitly wants deployment.
- NuGet package restore fails because a source is missing: inspect `NuGet.config` and installed package sources; use repo-local configuration where possible.
- API compile errors from a PR: inspect the target game/dependency versions before changing code. Prefer one target version rather than compatibility branches unless the user asks for multi-version support.