Add chat notes: /save and /nota, public and private

Players had nowhere to write anything down. Coordinates got pasted into
Discord, or lost. This adds notes to chat, with two scopes.

A private note is visible only to its author and everyone may write one
(canalhandia.nota, default true). A public note is broadcast and readable by
all, and writing one needs canalhandia.nota.publica (default op) — public
notes are a curated board, not a graffiti wall. Both permissions are declared
in plugin.yml: an undeclared Bukkit permission silently falls back to op-only,
which would have stopped normal players writing anything.

Every note stores where it was written. On a Minecraft server a note is nearly
always about a place — where the base is, where the spawner was found — so
coordinates are part of the model rather than optional metadata. Java players
get click-to-copy on them, the same affordance the death-coords message uses;
Bedrock renders no click event and gets the plain text. No teleport: the
plugin does not touch gameplay.

/save is the quick path. /save and /save coords pin the spot; /save <texto>
pins it with a note. Private on purpose — it is the command someone types
without reading help first, and the safe default there is the one that cannot
surprise anyone by broadcasting. /nota publica <texto> is the explicit way to
share.

Private notes are never sent to the AI, at any setting. The AI call leaves
this server for a third-party API, so a private note reaching it would be a
disclosure the author never agreed to. The filter lives inside
Notes.publicSummary — the only method the AI path calls — rather than at the
call site, so a future caller cannot get it wrong by accident. Public notes
are sent (ia.contexto-notas, default 10), which is what lets the AI answer
"onde fica a base?" from what players actually wrote down.

A note the viewer cannot see is reported as missing rather than as forbidden:
saying "that one is private" would confirm it exists, which is itself a leak.
Search runs through the same visibility filter, so it cannot become a way to
probe for someone else's text. Ids are never reused after a deletion, or
"/nota ver 2" would point at a different note than the one someone wrote down
a minute ago. Text is stripped of the section sign and control characters,
because a note is echoed into chat and could otherwise forge a line that looks
like it came from the server.

Scope parsing accepts the masculine and plural forms ("publico", "publicas")
alongside the canonical ones. Spelled out rather than derived: a blanket a-to-o
rewrite turns "privada" into "privodo", and the plural is exactly what tab
completion suggests, so it has to parse or the suggested command fails.

preflight.sh now checks all 18 commands and both new permissions.

218 tests, up from 176.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016pEyCmrAYHBFgpYjwFxKxh
This commit is contained in:
marcos
2026-08-07 23:46:55 +00:00
parent 5653836262
commit bc711a48c2
12 changed files with 1186 additions and 4 deletions
+16 -3
View File
@@ -49,16 +49,29 @@ else
fi
# Every command the code registers must exist in plugin.yml, or register()
# logs a warning and the command silently does nothing in game.
# Kept in step with Canalhandia.onEnable's register() list. A command that is
# registered in code but absent here logs a warning at boot and then silently
# does nothing in game, which is a hard failure to diagnose from inside.
CMDS="canalhandia curiosidade adivinha enquete ranking reagir reacoes \
palpite votar legal wow top f ia iap errado nota save"
missing=""
for cmd in canalhandia curiosidade adivinha enquete ranking reagir reacoes \
palpite votar legal wow top f ia iap errado; do
for cmd in $CMDS; do
unzip -p "$JAR" plugin.yml 2>/dev/null | grep -qE "^ ${cmd}:" || missing="$missing $cmd"
done
if [ -z "$missing" ]; then
pass "all 16 commands declared in plugin.yml"
pass "all $(echo $CMDS | wc -w) commands declared in plugin.yml"
else
bad "commands missing from plugin.yml:$missing"
fi
# Permissions the new features gate on. An undeclared Bukkit permission falls
# back to op-only, which would silently stop normal players writing notes.
for perm in canalhandia.nota canalhandia.nota.publica; do
if unzip -p "$JAR" plugin.yml 2>/dev/null | grep -q " ${perm}:"; then
pass "permission ${perm} declared"
else
bad "permission ${perm} MISSING — would default to op-only"
fi
done
# config.yml ships defaults; a jar without it means saveDefaultConfig() writes
# nothing and every setting silently falls back to the hardcoded default.
if unzip -p "$JAR" config.yml >/dev/null 2>&1; then