`requires_core` was only read and shown in the Modules table. A module
release that needs a newer core could be installed or updated anyway and
take the panel down, the update check offered such releases, and modules
left behind by a core rollback kept loading.
ModuleLoader::coreRequirementError() checks a manifest's constraint
(one or more `>= > <= < = == !=` conditions, a bare version meaning >=;
empty = any core; anything else unreadable and refused) against
XC_VM_VERSION, a nightly `X.Y.Z-dev.N` counting as X.Y.Z. It is applied:
- on load: the module is skipped with a log line, its dependents with it;
- on install (placeModuleFiles: zip, LB, standard set, platform) and on a
git/url update: refused before the installed copy is touched; a refused
copy the platform extracted into the modules directory is removed;
- in the update check: git offers the newest release whose module.json
(repository root, read from raw.githubusercontent.com, up to 10 tags)
this core can run, url honours requires_core in version.json;
- in the Modules table: the reason on the existing warning badge, now
labelled "Issue(s)".
The checks sit in small helpers, so discoverModules() and
updateModuleFromSource() come out simpler than before.