feat(rust): RunicNPC is required in the Rust bundle (runicnpc stage 9, D310)
All checks were successful
PR Checks / rust-gates (pull_request) Successful in 2m13s
All checks were successful
PR Checks / rust-gates (pull_request) Successful in 2m13s
- install/update refuse a Rust bundle that carries no RunicNPC, before anything is written, and say how to get one that does. - doctor fails when RunicNPC is missing or was never installed; a file edited by hand stays a warning, since it still loads. - compose-bundles.sh composes no Rust bundle without a RunicNPC release that answers the bridge's runicnpc_api (the published one stays), and fails a bridge that declares none; every Rust bundle now has `npc`. - A RunicNPC API-mismatch message lost its line continuation; restored. The bundle type still parses a bundle without `npc`, so doctor and an old pin can name it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
This commit is contained in:
@@ -377,44 +377,39 @@ compose_rust() {
|
||||
[ "$link_protocol" = "$plugin_protocol" ] || fail \
|
||||
"PROTOCOL MISMATCH — Rust-Link ${link_tag} speaks ${link_protocol}, Rust-Plugins ${plugin_tag} declares ${plugin_protocol}. The game link has no 409: a mismatched plugin would mis-parse. Fix: land the matching half and let its release cut, or bump Rust-Plugins/overlay.toml."
|
||||
|
||||
# RunicNPC (docs/runicnpc/PLAN.md D224): a third file, optional until its stage 9.
|
||||
# The bridge's manifest says which RunicNPC API its npc.* commands need
|
||||
# (`runicnpc_api`, from overlay.toml); the latest RunicNPC release is carried
|
||||
# only when it answers at least that. A bridge that needs none carries none: a
|
||||
# RunicNPC it cannot talk to would be an NPC plugin nobody manages.
|
||||
local npc='null' need npc_tag npc_tarball npc_manifest npc_api npc_carried=''
|
||||
# RunicNPC (docs/runicnpc/PLAN.md D224): a third file, REQUIRED since its stage 9
|
||||
# (D310) — the bridge refuses every NPC an event places without it, and the
|
||||
# installer refuses a Rust bundle that does not carry it. The bridge's manifest
|
||||
# says which RunicNPC API it needs (`runicnpc_api`, from overlay.toml); the
|
||||
# latest RunicNPC release is carried only when it answers at least that. With
|
||||
# none that does, the Rust bundle is not composed: the published one stays.
|
||||
local npc need npc_tag npc_tarball npc_manifest npc_api
|
||||
need="$(jq -r '.runicnpc_api // 0' "$manifest")"
|
||||
if [ "$need" -gt 0 ]; then
|
||||
rc=0
|
||||
resolve_latest "$RUNICNPC_REPO" runicnpc || rc=$?
|
||||
if [ "$rc" -eq 2 ]; then
|
||||
note "- **Rust**: the bridge needs RunicNPC API ${need}, and RunicNPC has not released yet — the bundle carries none."
|
||||
else
|
||||
npc_tag="$(release_tag runicnpc)"
|
||||
verify_assets runicnpc
|
||||
npc_tarball="$(single_tarball runicnpc)"
|
||||
npc_manifest="$(payload_manifest runicnpc "$npc_tarball" "$RUNICNPC_PREFIX" "$npc_tag")"
|
||||
[ -f "$(dirname "$npc_manifest")/RunicNPC.cs" ] \
|
||||
|| fail "the RunicNPC tarball has no ${RUNICNPC_PREFIX}/RunicNPC.cs"
|
||||
npc_api="$(jq -r '.api' "$npc_manifest")"
|
||||
echo "==> rust: RunicNPC ${npc_tag} api=${npc_api} | the bridge needs ${need}"
|
||||
if [ "$npc_api" -lt "$need" ]; then
|
||||
note "- **Rust**: RunicNPC \`${npc_tag}\` answers API ${npc_api} and the bridge needs ${need} — the bundle carries none until RunicNPC releases one that does."
|
||||
else
|
||||
npc="$(jq -n --arg repo "$RUNICNPC_REPO" --arg tag "$npc_tag" --slurpfile m "$npc_manifest" \
|
||||
--argjson asset "$(asset_json runicnpc "$npc_tarball")" \
|
||||
'{ repo: $repo, tag: $tag, version: ($tag | ltrimstr("v")), commit: $m[0].commit, api: $m[0].api,
|
||||
compat: { frameworks: { oxide: { min_version: $m[0].min_oxide_version },
|
||||
carbon: { min_version: $m[0].min_carbon_version } },
|
||||
requires_plugins: $m[0].requires_plugins },
|
||||
asset: $asset }')"
|
||||
jq -e '([.commit, .compat.frameworks[].min_version] | all(type == "string"))
|
||||
and (.api | type == "number") and (.compat.requires_plugins | type == "array")' <<<"$npc" >/dev/null \
|
||||
|| fail "the RunicNPC manifest is missing commit, api, a framework floor, or requires_plugins"
|
||||
npc_carried="$npc_tag"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
[ "$need" -gt 0 ] || fail \
|
||||
"Rust-Plugins ${plugin_tag} declares no runicnpc_api, and RunicNPC is required (D310) — a bridge older than RunicNPC's stage 4 cannot be bundled any more."
|
||||
rc=0
|
||||
resolve_latest "$RUNICNPC_REPO" runicnpc || rc=$?
|
||||
[ "$rc" -ne 2 ] || fail "the bridge needs RunicNPC API ${need}, and RunicNPC has not released — RunicNPC is required (D310)."
|
||||
npc_tag="$(release_tag runicnpc)"
|
||||
verify_assets runicnpc
|
||||
npc_tarball="$(single_tarball runicnpc)"
|
||||
npc_manifest="$(payload_manifest runicnpc "$npc_tarball" "$RUNICNPC_PREFIX" "$npc_tag")"
|
||||
[ -f "$(dirname "$npc_manifest")/RunicNPC.cs" ] \
|
||||
|| fail "the RunicNPC tarball has no ${RUNICNPC_PREFIX}/RunicNPC.cs"
|
||||
npc_api="$(jq -r '.api' "$npc_manifest")"
|
||||
echo "==> rust: RunicNPC ${npc_tag} api=${npc_api} | the bridge needs ${need}"
|
||||
[ "$npc_api" -ge "$need" ] || fail \
|
||||
"RunicNPC ${npc_tag} answers API ${npc_api} and Rust-Plugins ${plugin_tag} needs ${need} — RunicNPC is required (D310), so no Rust bundle is composed until it releases one that does."
|
||||
npc="$(jq -n --arg repo "$RUNICNPC_REPO" --arg tag "$npc_tag" --slurpfile m "$npc_manifest" \
|
||||
--argjson asset "$(asset_json runicnpc "$npc_tarball")" \
|
||||
'{ repo: $repo, tag: $tag, version: ($tag | ltrimstr("v")), commit: $m[0].commit, api: $m[0].api,
|
||||
compat: { frameworks: { oxide: { min_version: $m[0].min_oxide_version },
|
||||
carbon: { min_version: $m[0].min_carbon_version } },
|
||||
requires_plugins: $m[0].requires_plugins },
|
||||
asset: $asset }')"
|
||||
jq -e '([.commit, .compat.frameworks[].min_version] | all(type == "string"))
|
||||
and (.api | type == "number") and (.compat.requires_plugins | type == "array")' <<<"$npc" >/dev/null \
|
||||
|| fail "the RunicNPC manifest is missing commit, api, a framework floor, or requires_plugins"
|
||||
|
||||
jq -n \
|
||||
--arg link_repo "$RUST_LINK_REPO" --arg link_tag "$link_tag" \
|
||||
@@ -432,8 +427,8 @@ compose_rust() {
|
||||
compat: { frameworks: { oxide: { min_version: $m[0].min_oxide_version },
|
||||
carbon: { min_version: $m[0].min_carbon_version } },
|
||||
requires_plugins: $m[0].requires_plugins },
|
||||
asset: $p_asset } }
|
||||
+ (if $npc == null then {} else { npc: $npc } end)' > "$WORK/rust-s2.json"
|
||||
asset: $p_asset },
|
||||
npc: $npc }' > "$WORK/rust-s2.json"
|
||||
# A manifest missing a key would compose a `null` the installer then trusts.
|
||||
jq -e '([.payload.compat.frameworks[].min_version, .payload.commit] | all(type == "string"))
|
||||
and (.payload.compat.requires_plugins | type == "array")' "$WORK/rust-s2.json" >/dev/null \
|
||||
@@ -446,7 +441,7 @@ compose_rust() {
|
||||
local tag
|
||||
tag="$(fresh_tag "$PUBLISHED/v2/rust")"
|
||||
publish_doc "$PUBLISHED/v2/rust" "$tag" "$WORK/rust-s2.json"
|
||||
note "- **Rust**: published \`${tag}\` — Rust-Link \`${link_tag}\`, Rust-Plugins \`${plugin_tag}\`, protocol ${link_protocol}${npc_carried:+, RunicNPC \`${npc_tag}\`}."
|
||||
note "- **Rust**: published \`${tag}\` — Rust-Link \`${link_tag}\`, Rust-Plugins \`${plugin_tag}\`, protocol ${link_protocol}, RunicNPC \`${npc_tag}\`."
|
||||
echo "rust ${tag}" >> "$WORK/published-games.txt"
|
||||
}
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
# current.json, bundle-<tag>.json schema 1, ServUO: link + overlay
|
||||
# v2/servuo/current.json, bundle-<tag>.json schema 2, game "servuo"
|
||||
# v2/rust/current.json, bundle-<tag>.json schema 2, game "rust": Rust-Link + Rust-Plugins,
|
||||
# and RunicNPC when the bridge needs it (D224)
|
||||
# and RunicNPC, required since its stage 9 (D224, D310)
|
||||
#
|
||||
# Schema 2 (D146) names ONE game, with a `game` discriminant and a `payload`
|
||||
# that is an overlay for ServUO and a plugin for Rust. Schema 1 (D147) is still
|
||||
|
||||
Reference in New Issue
Block a user