papermc-skill 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/CHANGELOG.md +41 -0
  2. package/LICENSE +21 -0
  3. package/README.md +169 -0
  4. package/bin/cli.js +307 -0
  5. package/docs/01-modern-paper-architecture.md +172 -0
  6. package/docs/02-adventure-and-minimessage.md +160 -0
  7. package/docs/03-persistent-data-container.md +179 -0
  8. package/docs/04-commands-and-brigadier.md +157 -0
  9. package/docs/05-concurrency-and-folia.md +150 -0
  10. package/docs/06-events-and-listeners.md +163 -0
  11. package/docs/07-best-practices-and-perf.md +118 -0
  12. package/docs/08-gui-and-menus.md +198 -0
  13. package/docs/09-custom-items-and-combat.md +171 -0
  14. package/docs/10-database-and-storage.md +187 -0
  15. package/package.json +44 -0
  16. package/skills/paper-plugin-dev/SKILL.md +167 -0
  17. package/templates/paper-modern-template/.editorconfig +8 -0
  18. package/templates/paper-modern-template/.gradle/9.4.1/checksums/checksums.lock +0 -0
  19. package/templates/paper-modern-template/.gradle/9.4.1/checksums/md5-checksums.bin +0 -0
  20. package/templates/paper-modern-template/.gradle/9.4.1/checksums/sha1-checksums.bin +0 -0
  21. package/templates/paper-modern-template/.gradle/9.4.1/executionHistory/executionHistory.bin +0 -0
  22. package/templates/paper-modern-template/.gradle/9.4.1/executionHistory/executionHistory.lock +0 -0
  23. package/templates/paper-modern-template/.gradle/9.4.1/fileChanges/last-build.bin +0 -0
  24. package/templates/paper-modern-template/.gradle/9.4.1/fileHashes/fileHashes.bin +0 -0
  25. package/templates/paper-modern-template/.gradle/9.4.1/fileHashes/fileHashes.lock +0 -0
  26. package/templates/paper-modern-template/.gradle/9.4.1/fileHashes/resourceHashesCache.bin +0 -0
  27. package/templates/paper-modern-template/.gradle/9.4.1/gc.properties +0 -0
  28. package/templates/paper-modern-template/.gradle/buildOutputCleanup/buildOutputCleanup.lock +0 -0
  29. package/templates/paper-modern-template/.gradle/buildOutputCleanup/cache.properties +2 -0
  30. package/templates/paper-modern-template/.gradle/buildOutputCleanup/outputFiles.bin +0 -0
  31. package/templates/paper-modern-template/.gradle/file-system.probe +0 -0
  32. package/templates/paper-modern-template/.gradle/vcs-1/gc.properties +0 -0
  33. package/templates/paper-modern-template/build/classes/java/main/com/example/paperplugin/ExamplePaperPlugin.class +0 -0
  34. package/templates/paper-modern-template/build/classes/java/main/com/example/paperplugin/PaperPluginBootstrap.class +0 -0
  35. package/templates/paper-modern-template/build/classes/java/main/com/example/paperplugin/command/HelloCommand.class +0 -0
  36. package/templates/paper-modern-template/build/classes/java/main/com/example/paperplugin/data/PluginDataKeys.class +0 -0
  37. package/templates/paper-modern-template/build/classes/java/main/com/example/paperplugin/listener/PlayerEventListener.class +0 -0
  38. package/templates/paper-modern-template/build/classes/java/main/com/example/paperplugin/util/SchedulerAdapter.class +0 -0
  39. package/templates/paper-modern-template/build/tmp/compileJava/previous-compilation-data.bin +0 -0
  40. package/templates/paper-modern-template/build.gradle.kts +54 -0
  41. package/templates/paper-modern-template/gradle/wrapper/gradle-wrapper.jar +0 -0
  42. package/templates/paper-modern-template/gradle/wrapper/gradle-wrapper.properties +7 -0
  43. package/templates/paper-modern-template/gradlew +248 -0
  44. package/templates/paper-modern-template/gradlew.bat +93 -0
  45. package/templates/paper-modern-template/settings.gradle.kts +5 -0
  46. package/templates/paper-modern-template/src/main/java/com/example/paperplugin/ExamplePaperPlugin.java +35 -0
  47. package/templates/paper-modern-template/src/main/java/com/example/paperplugin/PaperPluginBootstrap.java +30 -0
  48. package/templates/paper-modern-template/src/main/java/com/example/paperplugin/command/HelloCommand.java +55 -0
  49. package/templates/paper-modern-template/src/main/java/com/example/paperplugin/data/PluginDataKeys.java +22 -0
  50. package/templates/paper-modern-template/src/main/java/com/example/paperplugin/listener/PlayerEventListener.java +61 -0
  51. package/templates/paper-modern-template/src/main/java/com/example/paperplugin/util/SchedulerAdapter.java +77 -0
  52. package/templates/paper-modern-template/src/main/resources/config.yml +10 -0
  53. package/templates/paper-modern-template/src/main/resources/paper-plugin.yml +9 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,41 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [1.0.0] - 2026-09-05
9
+
10
+ ### Added
11
+ - **Interactive NPX CLI Tool (`papermc-skill`)**:
12
+ - `npx papermc-skill create [name]`: Interactive project scaffolding for modern Paper & Folia plugins with customizable package name, author, and Minecraft target version.
13
+ - `npx papermc-skill install-skill [--global]`: Automated installation of the `paper-plugin-dev` AI agent skill for workspace (`.agents/skills/`) or global (`~/.gemini/config/skills/`).
14
+ - `npx papermc-skill docs [topic]`: Instant in-terminal viewer for architectural guides.
15
+ - **Modern Starter Template (`templates/paper-modern-template`)**:
16
+ - Gradle Kotlin DSL build setup (`build.gradle.kts`) with Java 21 toolchain and Foojay resolver convention.
17
+ - Paper 1.21.4 API dependency and instant testing tasks (`./gradlew runServer`, `./gradlew runFoliaServer`).
18
+ - Bundled official Gradle Wrapper (`gradlew`, `gradlew.bat`).
19
+ - Native Brigadier command registration via `LifecycleEvents.COMMANDS`.
20
+ - Kyori Adventure & MiniMessage integration without deprecated formatting codes.
21
+ - PersistentDataContainer (PDC) usage for player join tracking.
22
+ - Transparent Folia multi-threaded scheduler adapter (`SchedulerAdapter.java`).
23
+ - **Comprehensive Architectural & Technical Guides (`docs/`)**:
24
+ - `01-modern-paper-architecture.md`: Paperweight userdev, `paper-plugin.yml`, and `PluginBootstrap`.
25
+ - `02-adventure-and-minimessage.md`: Kyori Adventure Component, gradient tags, Title, Sound, and BossBar.
26
+ - `03-persistent-data-container.md`: PDC on Item, Entity, and Chunk with custom `PersistentDataType`.
27
+ - `04-commands-and-brigadier.md`: Paper native Brigadier commands and Incendo Cloud framework.
28
+ - `05-concurrency-and-folia.md`: Threaded Regions, Folia Schedulers, and thread safety.
29
+ - `06-events-and-listeners.md`: Paper-exclusive events, event priority, and custom events.
30
+ - `07-best-practices-and-perf.md`: Memory leak prevention, async chunk loading, and anti-patterns.
31
+ - `08-gui-and-menus.md`: Safe custom `InventoryHolder` menus with PDC click action buttons.
32
+ - `09-custom-items-and-combat.md`: Raycasting spells, particles, vanilla cooldowns, and combat mechanics.
33
+ - `10-database-and-storage.md`: Asynchronous database handling with SQLite and MySQL HikariCP pool.
34
+ - **AI Agent Skill Specification (`skills/paper-plugin-dev/SKILL.md`)**:
35
+ - Step-by-step workflow, dependency matrix, and ready-to-use code recipes for coding assistants.
36
+ - **Nine Cloned Open-Source Reference Plugins (`references/`)**:
37
+ - `squaremap`, `chunky`, `luckperms`, `miniplaceholders`, `vault-api`, `run-paper`, `decentholograms`, `bstats`, and `paperweight-test-plugin`.
38
+ - **Open-Source Governance & Security Suite**:
39
+ - MIT License (`LICENSE`), Code of Conduct (`CODE_OF_CONDUCT.md`), Contributing Guide (`CONTRIBUTING.md`), and Security Policy (`SECURITY.md`).
40
+ - GitHub Issue and Pull Request templates (`.github/ISSUE_TEMPLATE/`).
41
+ - Automated CI and NPM Publish workflows with provenance (`.github/workflows/`).
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Paper Minecraft Plugin Skill Contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,169 @@
1
+ <div align="center">
2
+
3
+ # 🎮 Paper Minecraft Plugin Skill & Knowledge Base
4
+
5
+ [![PaperMC](https://img.shields.io/badge/PaperMC-1.20.6%20%7C%201.21+-0098FF?style=for-the-badge&logo=minecraft&logoColor=white)](https://papermc.io)
6
+ [![Java](https://img.shields.io/badge/Java-21%2B%20LTS-ED8B00?style=for-the-badge&logo=openjdk&logoColor=white)](https://adoptium.net)
7
+ [![Folia](https://img.shields.io/badge/Folia-Multi--Threaded%20Ready-5865F2?style=for-the-badge)](https://github.com/PaperMC/Folia)
8
+ [![License: MIT](https://img.shields.io/badge/License-MIT-44CC11?style=for-the-badge)](LICENSE)
9
+ [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen?style=for-the-badge)](CONTRIBUTING.md)
10
+
11
+ **A comprehensive, production-grade knowledge base, architectural reference collection, starter template, and AI engineering skill for modern Minecraft Java Server plugin development on [PaperMC](https://papermc.io) and [Folia](https://github.com/PaperMC/Folia).**
12
+
13
+ [Features](#-features) • [Quickstart](#-quickstart) • [Architecture Guide](#-documentation-suite) • [Reference Plugins](#-cloned-reference-plugins) • [AI Skill](#-ai-agent-integration) • [Contributing](#-contributing)
14
+
15
+ ---
16
+
17
+ </div>
18
+
19
+ ## 🌟 Overview
20
+
21
+ The Minecraft server development ecosystem has undergone massive architectural shifts with Minecraft 1.20.5+ and 1.21+. Legacy Bukkit/Spigot habits—such as section sign color formatting (`§`), `plugin.yml` command registration, third-party NBT hacks, and blocking main-thread schedulers—lead to performance degradation, memory leaks, and fatal crashes on modern servers.
22
+
23
+ This repository serves as an **authoritative, single-source knowledge base** and **developer skill** designed to empower both human software engineers and AI pair-programming assistants to build performant, thread-safe, and idiomatic Paper plugins.
24
+
25
+ ---
26
+
27
+ ## ⚡ Key Architecture Highlights
28
+
29
+ | Modern Paper Standard | Legacy Spigot / Bukkit | Why Modern Matters |
30
+ | :--- | :--- | :--- |
31
+ | **Kyori Adventure & MiniMessage** | `ChatColor` & `§` color codes | Type-safe, component-based, 24-bit TrueColor/Hex gradients, interactive click/hover events, and zero string-injection risks. |
32
+ | **PersistentDataContainer (PDC)** | External NBT libraries / Lore parsing | Official native NBT storage on Items, Entities, Chunks, and Worlds. Serializes Java records seamlessly. |
33
+ | **Paper Native Brigadier** | `plugin.yml` & `setExecutor(...)` | Client-side syntax validation, auto tab-completion, and command routing directly inside Mojang's Brigadier engine. |
34
+ | **Regionized Threading (Folia)** | Single Main Thread `BukkitScheduler` | Scales across CPU cores via Threaded Regions. Uses `RegionScheduler`, `EntityScheduler`, and `AsyncScheduler`. |
35
+ | **Mojang Mappings (Paperweight)** | Spigot remapped / Obfuscated NMS | Zero-remapping runtime on Paper 1.20.5+; direct, clean access to Mojang server internals with `paperweight-userdev`. |
36
+
37
+ ---
38
+
39
+ ## 📚 Documentation Suite
40
+
41
+ Our documentation suite includes 10 comprehensive, in-depth architectural guides:
42
+
43
+ 1. **[01. Modern Paper Architecture](https://github.com/ardianryan/papermc-skill/blob/main/docs/01-modern-paper-architecture.md)**
44
+ *Deep dive into `paper-plugin.yml`, `PluginBootstrap` vs `JavaPlugin`, Gradle `paperweight-userdev`, and runtime Mojang mappings.*
45
+ 2. **[02. Adventure API & MiniMessage](https://github.com/ardianryan/papermc-skill/blob/main/docs/02-adventure-and-minimessage.md)**
46
+ *Hex colors, gradient tags, dynamic `TagResolver` placeholders, `ComponentLogger`, Titles, BossBars, and Sound playback.*
47
+ 3. **[03. PersistentDataContainer (PDC)](https://github.com/ardianryan/papermc-skill/blob/main/docs/03-persistent-data-container.md)**
48
+ *Storing custom data on ItemStacks, Entities, and Chunks; implementing custom `PersistentDataType<T, Z>` for POJO/record serialization.*
49
+ 4. **[04. Modern Command Systems: Brigadier & Cloud](https://github.com/ardianryan/papermc-skill/blob/main/docs/04-commands-and-brigadier.md)**
50
+ *Paper's native Brigadier command registration via `LifecycleEvents.COMMANDS`, argument parsing, suggestions, and Incendo Cloud.*
51
+ 5. **[05. Concurrency, Threading & Folia Compatibility](https://github.com/ardianryan/papermc-skill/blob/main/docs/05-concurrency-and-folia.md)**
52
+ *Threaded regions, region schedulers, entity schedulers, async schedulers, and universal cross-platform scheduling abstractions.*
53
+ 6. **[06. Event System & Listeners](https://github.com/ardianryan/papermc-skill/blob/main/docs/06-events-and-listeners.md)**
54
+ *Paper-exclusive events (`AsyncChatEvent`, `PrePlayerAttackEntityEvent`), event priority lifecycle, and custom event authoring.*
55
+ 7. **[07. Best Practices & Performance Optimization](https://github.com/ardianryan/papermc-skill/blob/main/docs/07-best-practices-and-perf.md)**
56
+ *Preventing GC memory leaks (UUID vs entity references), asynchronous chunk loading (`world.getChunkAtAsync`), and anti-patterns.*
57
+ 8. **[08. Modern GUI & Inventory Menus](https://github.com/ardianryan/papermc-skill/blob/main/docs/08-gui-and-menus.md)**
58
+ *Custom `InventoryHolder` verification, PDC-tagged interactive buttons, and bulletproof duplication-exploit prevention.*
59
+ 9. **[09. Custom Items, Abilities & Combat](https://github.com/ardianryan/papermc-skill/blob/main/docs/09-custom-items-and-combat.md)**
60
+ *Raycasting hitscan spells (`rayTraceEntities`), particle beam effects, vanilla visual cooldowns, and Adventure sound effects.*
61
+ 10. **[10. Asynchronous Database Storage](https://github.com/ardianryan/papermc-skill/blob/main/docs/10-database-and-storage.md)**
62
+ *SQLite and MySQL/PostgreSQL connection pooling via HikariCP, thread-safe asynchronous DAO pattern with `CompletableFuture`.*
63
+
64
+ ---
65
+
66
+ ## 🔍 Cloned Reference Plugins
67
+
68
+ Nine industry-standard open-source repositories have been cloned into [`references/`](references/) as real-world architectural blueprints:
69
+
70
+ | Repository | Source Origin | Core Concepts Demonstrated |
71
+ | :--- | :--- | :--- |
72
+ | **[`squaremap`](references/squaremap)** | `jpenilla/squaremap` | Developed by a PaperMC core developer. World rendering, `paperweight-userdev`, Incendo Cloud commands, and Folia multi-threading. |
73
+ | **[`chunky`](references/chunky)** | `pop4959/Chunky` | High-throughput async chunk loading (`world.getChunkAtAsync`), mathematical optimizations, and multi-platform platform adapters. |
74
+ | **[`luckperms`](references/luckperms)** | `LuckPerms/LuckPerms` | Enterprise-grade Java architecture: HikariCP connection pooling, custom internal event bus, caching hierarchy, and async I/O. |
75
+ | **[`miniplaceholders`](references/miniplaceholders)** | `MiniPlaceholders/MiniPlaceholders` | Advanced Kyori Adventure API usage, custom MiniMessage tag resolvers, and modern `paper-plugin.yml` bootstrapping. |
76
+ | **[`vault-api`](references/vault-api)** | `MilkBowl/VaultAPI` | The standard ecosystem bridge API for economy and permissions in Minecraft Java. |
77
+ | **[`run-paper`](references/run-paper)** | `jpenilla/run-paper` | The Gradle plugin source code for running instant local Paper and Folia test environments. |
78
+ | **[`decentholograms`](references/decentholograms)** | `DecentSoftware-eu/DecentHolograms` | Display entity manipulation, protocol packet handling, and dynamic per-player text rendering. |
79
+ | **[`bstats`](references/bstats)** | `Bastian/bStats-Metrics` | Industry-standard telemetry and metrics integration for Minecraft server plugins. |
80
+ | **[`paperweight-test-plugin`](references/paperweight-test-plugin)** | `PaperMC/paperweight-test-plugin` | Official PaperMC test project for `paperweight-userdev` Gradle configurations. |
81
+
82
+ ---
83
+
84
+ ## 🚀 Quickstart
85
+
86
+ ### Method 1: Instant Scaffolding via NPX (Recommended)
87
+
88
+ You can scaffold a new Paper plugin or install the AI skill instantly anywhere using `npx`:
89
+
90
+ ```bash
91
+ # 1. Interactively create a new modern Paper & Folia plugin
92
+ npx papermc-skill create MyAwesomePlugin
93
+
94
+ # 2. Or install the AI skill into your workspace (.agents/skills) or globally
95
+ npx papermc-skill install-skill --global
96
+
97
+ # 3. Read architectural guides right in your terminal
98
+ npx papermc-skill docs
99
+ ```
100
+
101
+ ### Method 2: Manual Clone & Local Server Test
102
+
103
+ A production-ready Gradle starter template is available in [`templates/paper-modern-template/`](templates/paper-modern-template).
104
+
105
+ #### Prerequisites
106
+ - **Java 21 SDK** installed ([Adoptium Temurin 21](https://adoptium.net/)):
107
+ - macOS: `brew install openjdk@21`
108
+ - Linux: `sudo apt install openjdk-21-jdk`
109
+ - Gradle is bundled inside the template via `./gradlew` (no manual Gradle install required).
110
+
111
+ #### Running a Local Test Server in 60 Seconds
112
+ ```bash
113
+ # 1. Navigate to the template project
114
+ cd templates/paper-modern-template
115
+
116
+ # 2. Launch an automated Paper test server
117
+ ./gradlew runServer
118
+
119
+ # 3. Or launch a multi-threaded Folia test server
120
+ ./gradlew runFoliaServer
121
+ ```
122
+ The task will automatically download the Paper/Folia runtime, accept the Mojang EULA, compile your code, and launch the server with your plugin enabled.
123
+
124
+ ---
125
+
126
+ ## 🤖 AI Agent Integration
127
+
128
+ This repository includes a standardized AI Assistant Skill in [`skills/paper-plugin-dev/SKILL.md`](skills/paper-plugin-dev/SKILL.md).
129
+
130
+ When working with AI coding assistants (such as Antigravity, GitHub Copilot, or Cursor):
131
+ - Point your assistant to `skills/paper-plugin-dev/SKILL.md`.
132
+ - The assistant will automatically adopt modern Paper 1.21+ standards, avoid deprecated Spigot methods, enforce Folia thread-safety, and use Adventure/PDC patterns out of the box.
133
+
134
+ ---
135
+
136
+ ## 📁 Repository Structure
137
+
138
+ ```text
139
+ minecraft-plugin-skill/
140
+ ├── .github/ # Issue & Pull Request templates
141
+ │ ├── ISSUE_TEMPLATE/
142
+ │ │ ├── bug_report.yml
143
+ │ │ └── feature_request.yml
144
+ │ └── pull_request_template.md
145
+ ├── docs/ # 10 In-depth architectural guides
146
+ ├── references/ # 9 Cloned open-source reference plugins
147
+ ├── skills/
148
+ │ └── paper-plugin-dev/ # AI Assistant Skill definition (SKILL.md)
149
+ ├── templates/
150
+ │ └── paper-modern-template/ # Standalone, runnable starter plugin project
151
+ ├── CODE_OF_CONDUCT.md # Contributor Covenant v2.1
152
+ ├── CONTRIBUTING.md # Comprehensive contribution guide
153
+ ├── LICENSE # MIT License
154
+ ├── README.md # Repository documentation
155
+ └── SECURITY.md # Security policy & reporting guidelines
156
+ ```
157
+
158
+ ---
159
+
160
+ ## 🤝 Contributing
161
+
162
+ Contributions are welcome! Please read our [Contributing Guidelines](CONTRIBUTING.md) and [Code of Conduct](CODE_OF_CONDUCT.md) before submitting pull requests or opening issues.
163
+
164
+ ---
165
+
166
+ ## 📄 License & Trademarks
167
+
168
+ - This project is licensed under the **[MIT License](LICENSE)**.
169
+ - *Minecraft* is a registered trademark of Mojang Synergies AB. This project is not affiliated with or endorsed by Mojang Synergies AB, Microsoft Corporation, or PaperMC.
package/bin/cli.js ADDED
@@ -0,0 +1,307 @@
1
+ #!/usr/bin/env node
2
+
3
+ import fs from 'node:fs';
4
+ import path from 'node:path';
5
+ import readline from 'node:readline';
6
+ import { fileURLToPath } from 'node:url';
7
+
8
+ const __filename = fileURLToPath(import.meta.url);
9
+ const __dirname = path.dirname(__filename);
10
+ const ROOT_DIR = path.resolve(__dirname, '..');
11
+
12
+ // ANSI Color Helpers (Pure zero-dependency, safe for all terminals)
13
+ const c = {
14
+ reset: '\x1b[0m',
15
+ bold: '\x1b[1m',
16
+ dim: '\x1b[2m',
17
+ cyan: '\x1b[36m',
18
+ green: '\x1b[32m',
19
+ yellow: '\x1b[33m',
20
+ red: '\x1b[31m',
21
+ gray: '\x1b[90m'
22
+ };
23
+
24
+ function printBanner() {
25
+ console.log(`
26
+ ${c.cyan}${c.bold} ____ __ __ ____
27
+ | _ \\ __ _ _ __ ___ _ __ | \\/ |/ ___| ____ _ _ _ _
28
+ | |_) / _\` | '_ \\ / _ \\ '__|____| |\\/| | | / ___|| | __(_) | |
29
+ | __/ (_| | |_) | __/ | |_____| | | | |___ \\___ \\| |/ / | | |
30
+ |_| \\__,_| .__/ \\___|_| |_| |_|\\____| |____/|_|\\_\\_|_|_|
31
+ |_| ${c.reset}${c.dim}Modern Paper & Folia Plugin Toolchain${c.reset}
32
+ `);
33
+ }
34
+
35
+ function prompt(question, defaultValue) {
36
+ const rl = readline.createInterface({
37
+ input: process.stdin,
38
+ output: process.stdout
39
+ });
40
+
41
+ return new Promise((resolve) => {
42
+ const q = defaultValue
43
+ ? `${c.cyan}?${c.reset} ${c.bold}${question}${c.reset} ${c.dim}(${defaultValue})${c.reset}: `
44
+ : `${c.cyan}?${c.reset} ${c.bold}${question}${c.reset}: `;
45
+
46
+ rl.question(q, (answer) => {
47
+ rl.close();
48
+ resolve(answer.trim() || defaultValue);
49
+ });
50
+ });
51
+ }
52
+
53
+ // Strict Input Sanitization (Prevents path traversal, code injection & illegal characters)
54
+ function sanitizePluginName(name) {
55
+ const sanitized = String(name || '').trim().replace(/[^a-zA-Z0-9_-]/g, '');
56
+ if (!sanitized) {
57
+ throw new Error('Plugin name must contain at least one alphanumeric character.');
58
+ }
59
+ return sanitized;
60
+ }
61
+
62
+ function sanitizePackageName(pkg) {
63
+ const sanitized = String(pkg || '').trim().toLowerCase().replace(/[^a-z0-9_.]/g, '');
64
+ if (!sanitized || sanitized.startsWith('.') || sanitized.endsWith('.') || sanitized.includes('..')) {
65
+ throw new Error('Invalid package name format. Example: com.example.myplugin');
66
+ }
67
+ return sanitized;
68
+ }
69
+
70
+ function sanitizeSafeDir(baseDir, targetName) {
71
+ const safeName = path.basename(targetName).replace(/[^a-zA-Z0-9_-]/g, '');
72
+ const resolved = path.resolve(baseDir, safeName);
73
+ if (!resolved.startsWith(path.resolve(baseDir))) {
74
+ throw new Error('Security Error: Path traversal attempt detected.');
75
+ }
76
+ return resolved;
77
+ }
78
+
79
+ function copyDirRecursive(src, dest, replacements = {}) {
80
+ fs.mkdirSync(dest, { recursive: true });
81
+ const entries = fs.readdirSync(src, { withFileTypes: true });
82
+
83
+ for (const entry of entries) {
84
+ const srcPath = path.join(src, entry.name);
85
+ const destPath = path.join(dest, entry.name);
86
+
87
+ if (entry.isDirectory()) {
88
+ copyDirRecursive(srcPath, destPath, replacements);
89
+ } else {
90
+ const content = fs.readFileSync(srcPath);
91
+
92
+ // Text replacement only on safe, recognized source file types
93
+ if (
94
+ entry.name.endsWith('.gradle.kts') ||
95
+ entry.name.endsWith('.yml') ||
96
+ entry.name.endsWith('.yaml') ||
97
+ entry.name.endsWith('.java') ||
98
+ entry.name.endsWith('.md')
99
+ ) {
100
+ let text = content.toString('utf-8');
101
+ for (const [key, value] of Object.entries(replacements)) {
102
+ text = text.replaceAll(key, value);
103
+ }
104
+ fs.writeFileSync(destPath, text, 'utf-8');
105
+ } else {
106
+ fs.copyFileSync(srcPath, destPath);
107
+ }
108
+
109
+ // Preserve executable permissions for gradlew wrapper
110
+ if (entry.name === 'gradlew') {
111
+ try {
112
+ fs.chmodSync(destPath, 0o755);
113
+ } catch (_) {}
114
+ }
115
+ }
116
+ }
117
+ }
118
+
119
+ async function handleCreate(targetDirArg) {
120
+ printBanner();
121
+ console.log(`${c.bold}Scaffolding a new Modern Paper Plugin...${c.reset}\n`);
122
+
123
+ const rawPluginName = await prompt('Plugin Name', targetDirArg || 'MyPaperPlugin');
124
+ const pluginName = sanitizePluginName(rawPluginName);
125
+ const targetDir = sanitizeSafeDir(process.cwd(), targetDirArg || pluginName.toLowerCase());
126
+
127
+ if (fs.existsSync(targetDir) && fs.readdirSync(targetDir).length > 0) {
128
+ console.error(`\n${c.red}Error:${c.reset} Target directory '${targetDir}' already exists and is not empty.\n`);
129
+ process.exit(1);
130
+ }
131
+
132
+ const rawPackage = await prompt('Package Group (e.g. com.example.plugin)', `com.example.${pluginName.toLowerCase().replace(/[^a-z0-9]/g, '')}`);
133
+ const packageName = sanitizePackageName(rawPackage);
134
+
135
+ const rawAuthor = await prompt('Author Name', 'Developer');
136
+ const authorName = String(rawAuthor || 'Developer').replace(/[^a-zA-Z0-9_\s-]/g, '').trim() || 'Developer';
137
+
138
+ const mcVersion = await prompt('Paper Minecraft Version', '1.21.4');
139
+ const cleanMcVersion = String(mcVersion || '1.21.4').replace(/[^0-9.]/g, '') || '1.21.4';
140
+
141
+ console.log(`\n${c.yellow}Creating project at:${c.reset} ${c.dim}${targetDir}${c.reset}`);
142
+
143
+ const templateDir = path.join(ROOT_DIR, 'templates', 'paper-modern-template');
144
+ if (!fs.existsSync(templateDir)) {
145
+ console.error(`${c.red}Error:${c.reset} Starter template directory not found at ${templateDir}`);
146
+ process.exit(1);
147
+ }
148
+
149
+ // 1. Copy base template with sanitized replacements
150
+ copyDirRecursive(templateDir, targetDir, {
151
+ 'ModernPaperTemplate': pluginName,
152
+ 'paper-modern-template': pluginName.toLowerCase().replace(/[^a-z0-9_-]/gi, '-'),
153
+ 'com.example.paperplugin': packageName,
154
+ '1.21.4': cleanMcVersion,
155
+ 'Developer': authorName
156
+ });
157
+
158
+ // 2. Refactor Java package directory structure if package changed from com.example.paperplugin
159
+ const defaultPackagePath = path.join(targetDir, 'src', 'main', 'java', 'com', 'example', 'paperplugin');
160
+ const targetPackagePath = path.join(targetDir, 'src', 'main', 'java', ...packageName.split('.'));
161
+
162
+ if (defaultPackagePath !== targetPackagePath && fs.existsSync(defaultPackagePath)) {
163
+ fs.mkdirSync(targetPackagePath, { recursive: true });
164
+ const files = fs.readdirSync(defaultPackagePath);
165
+ for (const file of files) {
166
+ fs.renameSync(path.join(defaultPackagePath, file), path.join(targetPackagePath, file));
167
+ }
168
+ // Cleanup empty old dirs safely
169
+ try {
170
+ fs.rmSync(path.join(targetDir, 'src', 'main', 'java', 'com', 'example'), { recursive: true, force: true });
171
+ } catch (_) {}
172
+ }
173
+
174
+ console.log(`\n${c.green}${c.bold}✔ Project created successfully!${c.reset}\n`);
175
+ console.log(`${c.bold}To start developing and run your test server:${c.reset}`);
176
+ console.log(` ${c.cyan}cd${c.reset} ${path.relative(process.cwd(), targetDir) || '.'}`);
177
+ console.log(` ${c.cyan}./gradlew runServer${c.reset} ${c.gray}# Launches Paper test server${c.reset}`);
178
+ console.log(` ${c.cyan}./gradlew runFoliaServer${c.reset} # Launches Folia multi-threaded test server${c.reset}\n`);
179
+ }
180
+
181
+ async function handleInstallSkill(options) {
182
+ printBanner();
183
+ console.log(`${c.bold}Installing 'paper-plugin-dev' Agent Skill...${c.reset}\n`);
184
+
185
+ const isGlobal = options.includes('--global') || options.includes('-g');
186
+ const homeDir = process.env.HOME || process.env.USERPROFILE;
187
+
188
+ let targetSkillDir;
189
+ if (isGlobal) {
190
+ targetSkillDir = path.join(homeDir, '.gemini', 'config', 'skills', 'paper-plugin-dev');
191
+ } else {
192
+ // Current workspace customization root
193
+ targetSkillDir = path.resolve(process.cwd(), '.agents', 'skills', 'paper-plugin-dev');
194
+ }
195
+
196
+ const srcSkillDir = path.join(ROOT_DIR, 'skills', 'paper-plugin-dev');
197
+ if (!fs.existsSync(srcSkillDir)) {
198
+ console.error(`${c.red}Error:${c.reset} Source skill directory not found at ${srcSkillDir}`);
199
+ process.exit(1);
200
+ }
201
+
202
+ copyDirRecursive(srcSkillDir, targetSkillDir);
203
+
204
+ console.log(`${c.green}${c.bold}✔ Skill successfully installed!${c.reset}`);
205
+ console.log(` Target: ${c.dim}${targetSkillDir}${c.reset}\n`);
206
+ console.log(`Your AI coding agent can now automatically discover and load the ${c.bold}paper-plugin-dev${c.reset} skill.`);
207
+ }
208
+
209
+ function handleDocs(topic) {
210
+ const docsDir = path.join(ROOT_DIR, 'docs');
211
+ if (!fs.existsSync(docsDir)) {
212
+ console.error(`${c.red}Error:${c.reset} Docs directory not found.`);
213
+ process.exit(1);
214
+ }
215
+
216
+ const files = fs.readdirSync(docsDir).filter(f => f.endsWith('.md')).sort();
217
+
218
+ if (!topic) {
219
+ printBanner();
220
+ console.log(`${c.bold}Available Architectural & Technical Guides:${c.reset}\n`);
221
+ files.forEach((file, index) => {
222
+ console.log(` ${c.cyan}${String(index + 1).padStart(2, '0')}.${c.reset} ${c.bold}${file}${c.reset}`);
223
+ });
224
+ console.log(`\nTo view a specific guide, run: ${c.cyan}npx papermc-skill docs <number|keyword>${c.reset}\n`);
225
+ return;
226
+ }
227
+
228
+ const cleanTopic = String(topic).replace(/[^a-zA-Z0-9_-]/g, '');
229
+ const matched = files.find(f => f.toLowerCase().includes(cleanTopic.toLowerCase()) || f.startsWith(cleanTopic.padStart(2, '0')));
230
+ if (!matched) {
231
+ console.error(`${c.red}No guide found matching '${topic}'. Run 'npx papermc-skill docs' for a list.${c.reset}`);
232
+ return;
233
+ }
234
+
235
+ const content = fs.readFileSync(path.join(docsDir, matched), 'utf-8');
236
+ console.log(`\n${c.green}${c.bold}--- ${matched} ---${c.reset}\n`);
237
+ console.log(content);
238
+ }
239
+
240
+ function printHelp() {
241
+ printBanner();
242
+ console.log(`${c.bold}Usage:${c.reset}
243
+ npx papermc-skill <command> [options]
244
+
245
+ ${c.bold}Commands:${c.reset}
246
+ ${c.cyan}create [name]${c.reset} / ${c.cyan}init [name]${c.reset} Scaffold a modern Paper & Folia plugin project
247
+ ${c.cyan}install-skill [--global]${c.reset} Install the AI skill into workspace (.agents) or global (~/.gemini)
248
+ ${c.cyan}docs [number|keyword]${c.reset} Browse or print documentation guides
249
+ ${c.cyan}help${c.reset} / ${c.cyan}--help${c.reset} Display this help screen
250
+ ${c.cyan}--version${c.reset} Show version information
251
+
252
+ ${c.bold}Examples:${c.reset}
253
+ ${c.dim}# Create a new Paper plugin in current directory${c.reset}
254
+ npx papermc-skill create MyAwesomePlugin
255
+
256
+ ${c.dim}# Install AI skill globally for your coding agent${c.reset}
257
+ npx papermc-skill install-skill --global
258
+
259
+ ${c.dim}# View the Adventure API and MiniMessage guide${c.reset}
260
+ npx papermc-skill docs adventure
261
+ `);
262
+ }
263
+
264
+ // CLI Router
265
+ async function main() {
266
+ const args = process.argv.slice(2);
267
+ const command = args[0] || 'create';
268
+
269
+ switch (command) {
270
+ case 'create':
271
+ case 'init':
272
+ case 'new':
273
+ await handleCreate(args[1]);
274
+ break;
275
+ case 'install-skill':
276
+ case 'install':
277
+ case 'skill':
278
+ await handleInstallSkill(args.slice(1));
279
+ break;
280
+ case 'docs':
281
+ case 'doc':
282
+ case 'guide':
283
+ handleDocs(args[1]);
284
+ break;
285
+ case '--version':
286
+ case '-v': {
287
+ const pkg = JSON.parse(fs.readFileSync(path.join(ROOT_DIR, 'package.json'), 'utf-8'));
288
+ console.log(`papermc-skill v${pkg.version}`);
289
+ break;
290
+ }
291
+ case 'help':
292
+ case '--help':
293
+ case '-h':
294
+ default:
295
+ if (command.startsWith('-')) {
296
+ printHelp();
297
+ } else {
298
+ await handleCreate(command);
299
+ }
300
+ break;
301
+ }
302
+ }
303
+
304
+ main().catch((err) => {
305
+ console.error(`\n${c.red}Error:${c.reset}`, err.message);
306
+ process.exit(1);
307
+ });