The compose job carries the latest RunicNPC release that answers the API the
bridge's manifest declares (runicnpc_api), verified against its SHA256SUMS
like the other two; none when the bridge needs none, RunicNPC has not
released, or its API is too old, each said in the summary. Walked against a
mock Gitea in all three cases.
The installer reads the optional npc component (older bundles still parse),
fetches and checks RunicNPC's tarball against its manifest, places
RunicNPC.cs before the bridge in each instance's plugins directory, records
it, puts it back on update when edited or deleted, reports it in doctor, and
removes it on uninstall. Its data directory is never touched. Kits joins the
required plugins it reports.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
Rust-Plugins now releases a ZoneManager helper, RunicGatewayZones.cs, beside
RunicGateway.cs (docs/modules/rust/PLAN_FIXES.md D181, D182), and the org lead
decided it is installed by default. The tarball reader took only the bridge,
so the helper would have been downloaded and dropped.
- plugin::read_tarball reads every other .cs the release's manifest lists in
`files`, and refuses the release when one is missing, does not match its own
sha256, or is not a plain `<Name>.cs` (the name is written into a plugins
directory, so nothing in a tarball may reach outside it). A .cs the manifest
does not list is ignored, so a release older than helpers has none.
- install/update place each helper before the bridge, in place like the
bridge (Oxide and Carbon reload on a change, not on a rename), put back one
that was deleted or edited, and remove one a later release stops shipping.
- The record gains per-instance `helpers` (path + sha256). It is absent from
every record written before this and reads back as none.
- doctor warns — never fails — on a missing or edited helper and says what
the bridge loses without it; uninstall removes helpers before the bridge.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
Module-rust phase 18, step 5 of docs/modules/rust/PLAN.md §34.2.7 (D146,
D148, D149, D153).
Bundles: ServUO is read at schema 2 from v2/servuo/ and lowered into the
schema-1 model. Schema 1 at the root is the fallback, so a pin from before
schema 2 still reproduces. Rust bundles are read from v2/rust/. v2 reads use
the contents API, because /raw/ is CDN-cached for six hours.
--game rust runs install, update, doctor and uninstall for Rust servers
(src/rustgame/):
- the framework is detected from its marker files, which were read off both
rigs; both or neither is refused;
- --server-id names an instance: its own service (runicgateway-rust@<id>, or
RunicGatewayRust-<id>), config, database and ports;
- the plugin config is written once, with ServerId and Port only. An existing
one is never rewritten, and one naming another server refuses the run;
- each instance's sidecar.toml is written once with its ports and an absolute
database path, and the sidecar generates the token into it;
- one binary per host. update moves every instance, and a replaced binary
restarts all of them;
- doctor checks the plugin file hash, the plugin config's ServerId, the
required uMod plugins (a warning), the service and /health, and passes when
the plugin is connected;
- uninstall removes our plugin and keeps its config. --purge also removes the
sidecar config and database. The last instance takes the binary, the
template and the record, and the shared user only when no ServUO record
remains.
service.rs takes the service name as a parameter internally. The ServUO
public API is unchanged.
Finding: Carbon 2.0.259's config.json has no folder keys, so carbon/plugins
and carbon/configs are what the installer uses. The plan expected a moved
directory to be readable there.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY