Files
plugin-helper/docs/review-07.09.2026.md
T
2026-07-09 19:08:14 -07:00

4.5 KiB
Raw Blame History

Findings

  • High: install state is still keyed by instance name, not a concrete installation. state.py writes everything under instances/<instance>, and the TUI gives every discovered root the same runtime.state_root in cli.py. That is fine only if Linux and Windows installs never share a state dir. For package-manager ambitions, introduce an install_id derived from profile/root/path, and split reusable asset cache from per-install state.

  • High: apply_plan is not transactional. It backs up and writes files one by one, then saves state at the end in installer.py. If extraction/copy fails mid-plan, the game tree can be half-mutated without matching install state. A future package manager wants transactions/generations: stage, apply, record transaction, and have a first-class rollback command.

  • Medium-high: installed state records files but not the installed package identity. installer.py stores path, sha256, and size, but not repo/tag/asset/source URL/source hash/reason. The report then uses the current lockfile to describe installed versions, which can drift after a lock update. Record the lock identity into install state at apply time.

  • Medium-high: dependency handling is intentionally thin. Dependency.constraint exists in models.py, but planner.py only expands required dependency IDs and does not enforce constraints, conflicts, loadAfter, loadBefore, BeatMods version-id closures, or “provides” relationships. That is the next big unlock for package-manager behavior.

  • Medium: the agent skills have a few stale or conflicting operational rules. The manager skill still tells agents to inspect/edit registry/plugins.toml in .agents/skills/beatsaber-plugin-manager/SKILL.md, while the project has moved to registry/plugins/*.toml. The builder skill says PR checkouts go under <state_dir>/build in .agents/skills/beatsaber-plugin-builder/SKILL.md, while AGENTS.md says GitHub plugin source checkouts should live under ~/src/<owner>/<repo>. That will make agents inconsistent.

Skills

I would not collapse the three skills into one. They are conceptually different:

  • beatsaber-plugin-manager: mutating install/update/bootstrap workflow.
  • beatsaber-plugin-update-auditor: read-mostly audit/report workflow.
  • beatsaber-plugin-builder: source build workflow.

But I would consolidate shared policy into references, then have each skill import that mental model:

  • references/repo-workflow.md: repo root, .venv, PYTHONPATH=src, dirty worktree rules, validation commands.
  • references/state-and-profiles.md: .state, profiles, install identity, source checkout location.
  • references/artifact-policy.md: GitHub first, BeatMods metadata/fallback, private sources, checksum policy.
  • references/live-validation.md: smoketest and process cleanup.

That removes duplicated drift while preserving good trigger boundaries.

Design Direction

Yes, the script design is useful. The best parts are exactly the right bones for a real package manager: registry, locks, dry-run plans, hash checks, managed install state, bootstrap as its own phase, update audit, and known-good sets.

The next shape Id aim for is:

  • packages/registry: identity, source aliases, install strategy, metadata extraction rules.
  • versions/locks: selected package versions/artifacts/evidence for each Beat Saber version.
  • cache/downloads: content-addressed artifacts reusable across installs.
  • installs/<install_id>: installed packages, transactions, bootstrap, known-good generations, backups.
  • commands like resolve, fetch, plan, apply, rollback, audit, verify.

Beat Saber plugins are heterogeneous in packaging, but homogeneous enough in runtime shape (Plugins, Libs, IPA/Pending, root BSIPA files) that this can become a nice small package manager. The trick is to normalize artifacts into a planned file tree before touching the game.

Validation: compileall passed, and unittest discover passed: 75 tests, 1 skipped.