diff --git a/AGENTS.md b/AGENTS.md index a9a5388..766a648 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,21 +1,22 @@ # AGENTS.md -Guidance for agents working on Minefetch, a Kotlin PaperMC plugin that displays host system information generated by external Fastfetch watcher scripts. +Guidance for agents working on Minefetch, a Kotlin Paper plugin plus host-side Fastfetch producers. -## Boundaries +## Current data flow -- `src/main/kotlin/` contains plugin lifecycle, command handling, safe sysinfo reading, and update checking. -- `src/main/resources/plugin.yml` defines commands and permissions. -- `scripts/` contains macOS/Linux/Windows installation and watcher jobs plus Fastfetch configuration. The plugin reads their output; it must not shell out on every command. +- `MinefetchPlugin` hard-codes the container path `/sysinfo/host.json`, registers `/minefetch` (`/sysinfo`), starts a best-effort async GitHub update check, and collects live JVM/Paper metrics. +- Every command calls `SysInfoReader.readAndRefresh()`: it creates `/sysinfo/.refresh`, then calls `Thread.sleep(250)` up to 20 times on the Paper command thread while waiting for the trigger to disappear. This can block the server thread for five seconds and must not be described as asynchronous. +- The shell/PowerShell watcher polls `.refresh` every 500 ms, removes it, writes Fastfetch JSON to `host.json.tmp`, and atomically renames it. One-shot update scripts use the same temporary-file pattern. +- `SysInfoReader` tolerates missing/malformed JSON by returning null and extracts known Fastfetch modules into `HostInfo`. The command renders host values plus server version, Java, players, JVM heap, one-minute TPS, plugin count, and cores. +- Gradle uses JDK 26 while targeting Java/JVM 25, shades Kotlin and relocated `org.json`, and treats Paper as compile-only. Install scripts build the `-all.jar` and overwrite `Minefetch.jar` in an operator-selected plugin directory. -## Invariants +## Invariants and safety -- Treat the sysinfo file as untrusted, concurrently replaced input. Bound its size, decode safely, and handle missing/partial files. -- Do not expose secrets, usernames, internal IPs, or arbitrary host files to players. -- Keep file I/O and update checks off the server thread; send Paper messages on the main thread. -- Install scripts must be idempotent and avoid overwriting unrelated launchd/tasks/files. -- Maintain equivalent data keys across shell and PowerShell watchers. +- Move refresh waiting and file I/O off the Paper main thread before increasing work or timeouts; marshal only final messages back to the sender safely. +- Preserve the `.refresh`/temporary-file atomic handshake across Bash and PowerShell. Handle stale triggers, watcher absence, interrupted writes, BOM/encoding differences, and concurrent commands. +- Treat host JSON as untrusted and bound its size. Avoid exposing host secrets, private addresses, usernames, mounts, or arbitrary Fastfetch modules to all players; `minefetch.use` defaults to true. +- Keep `plugin.yml`, Gradle/plugin versions, README/runbooks, fixed mount path, and script defaults synchronized. ## Validation -Run `./gradlew build`. Run `shellcheck`/`bash -n` for shell changes and parse-check PowerShell where available. Test plugin enable, permissions, missing/stale/malformed/oversized sysinfo, atomic watcher updates, reload, and update-check failure on a test Paper server. Never commit generated host data or build output. +Run `./gradlew build` with JDK 26, `bash -n` plus `shellcheck` on shell scripts, and PowerShell parsing/static checks where available. There is no automated test suite, so test on a disposable Paper 26.1 server with and without a watcher: missing/null/malformed/partial/oversized JSON, stale triggers, two simultaneous commands, five-second timeout, atomic refresh, permissions, TPS/memory formatting, update-check failure, and clean reload. Never commit generated host data or build output.