minercon 3.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 (44) hide show
  1. package/CHANGELOG.md +439 -0
  2. package/LICENSE +22 -0
  3. package/README.md +401 -0
  4. package/images/icon.png +0 -0
  5. package/out/ansi.js +123 -0
  6. package/out/argumentHint.js +43 -0
  7. package/out/bukkitHelpParsing.js +62 -0
  8. package/out/cli.js +253 -0
  9. package/out/cliConfig.js +141 -0
  10. package/out/commandLine.js +28 -0
  11. package/out/commandSuggestions.js +202 -0
  12. package/out/commandTree.js +46 -0
  13. package/out/commandTreeCache.js +171 -0
  14. package/out/commandTreeCrawler.js +583 -0
  15. package/out/commandTreeParsingBrigadier.js +426 -0
  16. package/out/commandTreeParsingBukkit.js +116 -0
  17. package/out/commandTreeSuggestions.js +142 -0
  18. package/out/completionBackend.js +94 -0
  19. package/out/completionEngine.js +376 -0
  20. package/out/completionQueries.js +86 -0
  21. package/out/completionsBackend.js +97 -0
  22. package/out/connectionManager.js +209 -0
  23. package/out/displayArgumentHint.js +43 -0
  24. package/out/displayCommandTree.js +115 -0
  25. package/out/displaySuggestion.js +282 -0
  26. package/out/extension.js +190 -0
  27. package/out/helpTextParsing.js +445 -0
  28. package/out/historySearch.js +46 -0
  29. package/out/historyStore.js +126 -0
  30. package/out/lineEditor.js +525 -0
  31. package/out/localCommandTree.js +541 -0
  32. package/out/logger.js +14 -0
  33. package/out/minercon +253 -0
  34. package/out/pager.js +168 -0
  35. package/out/pagination.js +142 -0
  36. package/out/rconClient.js +97 -0
  37. package/out/rconConnectionManager.js +238 -0
  38. package/out/rconProtocol.js +421 -0
  39. package/out/rconSession.js +920 -0
  40. package/out/rconTerminal.js +80 -0
  41. package/out/suggestionDisplay.js +286 -0
  42. package/out/terminalOutput.js +110 -0
  43. package/out/unpaginate.js +30 -0
  44. package/package.json +138 -0
package/README.md ADDED
@@ -0,0 +1,401 @@
1
+ # Minercon
2
+
3
+ A full-featured RCON client for Minecraft servers — available both as a
4
+ **VS Code extension** (integrated terminal panel) and as a **standalone CLI
5
+ tool** (`minercon`) that runs in any terminal.
6
+
7
+ ![Version](https://img.shields.io/badge/version-3.0.0-blue)
8
+ ![VS Code](https://img.shields.io/badge/VS%20Code-%5E1.95.0-green)
9
+ ![License](https://img.shields.io/badge/license-MIT-brightgreen)
10
+
11
+ > A heavy fork of "Minecraft RCON Terminal"
12
+
13
+ ![Demo](images/demo-autocomplete.gif)
14
+
15
+ ---
16
+
17
+ ## Features
18
+
19
+ **Command completion**
20
+ - Real-time suggestions as you type, cycling with Tab / Shift+Tab
21
+ - Argument hints showing the full usage signature of the current command
22
+ - Works with vanilla, Bukkit/Spigot/Paper, and plugin-extended servers
23
+ - When the [Paper TabComplete](paper-plugin/) or [Spigot TabComplete](spigot-plugin/)
24
+ plugins or the [Fabric TabComplete](fabric-mod/) mod
25
+ is installed on your server, completions come directly from the
26
+ server (fastest, most accurate). Without it, the extension builds a local
27
+ command tree by crawling `/help` output once per server and caching it.
28
+
29
+ **Emacs-style line editing**
30
+ - Full cursor movement, word-jump, selection, and kill/yank (session-local kill ring)
31
+ - Scrollable command history, persistent across reconnects
32
+
33
+ **Ctrl-r command history search** -- with a filtered suggestion list
34
+
35
+ **Minecraft color codes** — server responses render with full `§` color support
36
+
37
+ **Robust connection handling** — exponential-backoff auto-reconnect on drop;
38
+ TCP keepalive to detect silent disconnects
39
+
40
+ **No response truncation** — custom RCON protocol implementation handles
41
+ fragmented multi-packet responses correctly (vanilla server `/help` returns
42
+ 300+ commands in full)
43
+
44
+ ---
45
+
46
+ ## Server setup
47
+
48
+ Add these lines to `server.properties` and restart:
49
+
50
+ ```properties
51
+ enable-rcon=true
52
+ rcon.port=25575
53
+ rcon.password=your-secure-password
54
+ ```
55
+
56
+ The password is only needed at connect time and is never written to disk by
57
+ this tool.
58
+
59
+ ---
60
+
61
+ ## VS Code extension
62
+
63
+ ### Installation
64
+
65
+ Search **"Minercon"** in the VS Code Extensions panel, or
66
+ install from a `.vsix` file:
67
+
68
+ ```
69
+ Ctrl+Shift+P → Extensions: Install from VSIX...
70
+ ```
71
+
72
+ ### Connecting
73
+
74
+ | Command (Ctrl+Shift+P) | Description |
75
+ |---|---|
76
+ | Minercon: Connect to Server | Connect using saved defaults, or prompt if none saved |
77
+ | Minercon: Connect with New Credentials | Always prompt for host, port, and password |
78
+ | Minercon: Save Current Connection as Default | Save the current connection's host and port; password goes to VS Code's secure secret storage |
79
+
80
+ You can also open a terminal via the **Terminal** menu → **New Terminal** →
81
+ select **Minecraft Server** from the terminal profile picker.
82
+
83
+ Multiple RCON terminals can be open simultaneously, each to a different server.
84
+
85
+ ### VS Code settings
86
+
87
+ ```json
88
+ {
89
+ "minercon.defaultHost": "localhost",
90
+ "minercon.defaultPort": 25575
91
+ }
92
+ ```
93
+
94
+ The password is not stored in settings — it lives in VS Code's encrypted
95
+ secret storage.
96
+
97
+ ---
98
+
99
+ ## CLI tool
100
+
101
+ ### Installation
102
+
103
+ ```sh
104
+ npm install -g minercon
105
+ ```
106
+
107
+ Or, after cloning and building locally:
108
+
109
+ ```sh
110
+ npm run compile
111
+ node out/minercon --help
112
+ ```
113
+
114
+ ### Usage
115
+
116
+ ```
117
+ minercon [host] [port] [options]
118
+
119
+ Options:
120
+ -p, --password <pw> RCON password
121
+ --save Save host/port/history-size to ~/.config/minercon/config.json
122
+ --log-file <path> Write log output to a file instead of the console
123
+ --log-level <level> consola log level, e.g. debug, info, warn, error (default: info)
124
+ --history-size <n> Number of commands to remember in history (default: 100)
125
+ --no-plugin Skip the server-side tab-complete plugin probe (manual
126
+ testing only; not persisted to config)
127
+ --no-unpaginate Do not request unpaginated output via the plugin
128
+ (keep the server's small pages)
129
+ --no-pager Do not page tall output; print it all at once
130
+ -h, --help Show help
131
+
132
+ Environment variables:
133
+ MCRCON_PASSWORD RCON password (used when --password is not given)
134
+ MCRCON_LOG_FILE Log file path (used when --log-file is not given)
135
+ MCRCON_LOG_LEVEL Log level (used when --log-level is not given)
136
+ MCRCON_HISTORY_SIZE History size (used when --history-size is not given)
137
+ MCRCON_UNPAGINATE Set to 0 to disable unpaginated output (default on)
138
+ MCRCON_PAGER Set to 0 to disable the output pager (default on)
139
+ ```
140
+
141
+ **Password handling:** the CLI never writes the password to disk. Supply it
142
+ with `--password`, the `MCRCON_PASSWORD` environment variable, or leave both
143
+ unset and you will be prompted with masked input.
144
+
145
+ **Saved host/port:** `--save` writes host and port (never the password) to
146
+ `~/.config/minercon/config.json`. On subsequent invocations, those
147
+ values are used as defaults so you can just run `minercon` with no
148
+ arguments.
149
+
150
+ **Kill/yank:** the CLI uses an in-process kill ring (Ctrl+K stashes text;
151
+ Ctrl+Y yanks it back). The kill ring is not connected to the system clipboard.
152
+ Ctrl+X / Ctrl+C-with-selection do the same within the session.
153
+
154
+ **Log output:** diagnostic messages are printed via
155
+ [consola](https://github.com/unjs/consola), colored and leveled by default.
156
+ Use `--log-file` to redirect that output to a file instead (useful when
157
+ console output would interfere with piped output or the interactive
158
+ session). Use `--log-level debug` for verbose per-command RCON send/receive
159
+ logging.
160
+
161
+ **History size:** `--history-size` controls how many commands are remembered
162
+ for `Up`/`Ctrl+P`/`Ctrl+R` recall and the `.history` command, and (with
163
+ `--save`) persists to the saved config.
164
+
165
+ **`--no-plugin`:** forces local mode (crawling `/help` for tab completion)
166
+ even if the server-side TabComplete plugin/mod is installed. Intended for
167
+ testing the local-mode crawl — see [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md#terminology)
168
+ for what "local mode" vs. "plugin mode" means.
169
+
170
+ **Unpaginated output & pager:** on Paper/Spigot, the TabComplete plugin exposes
171
+ an `rcat` command that re-runs a command as the console so Bukkit's tiny RCON
172
+ pagination (e.g. the `/help` "Help: Index (1/N)" pages) is bypassed — the
173
+ terminal requests this automatically in plugin mode. Output taller than the
174
+ window is then shown through a built-in pager (Space: more, `G`: all, `q`:
175
+ quit) that keeps the content in your terminal scrollback. Disable either with
176
+ `--no-unpaginate` / `--no-pager`, the `MCRCON_UNPAGINATE` / `MCRCON_PAGER`
177
+ environment variables, or the `minercon.unpaginateOutput` /
178
+ `minercon.terminalPager` VS Code settings. See
179
+ [docs/UNPAGINATED_OUTPUT.md](docs/UNPAGINATED_OUTPUT.md).
180
+
181
+ ### Quick examples
182
+
183
+ ```sh
184
+ # One-off connection (prompts for password)
185
+ minercon localhost 25575
186
+
187
+ # Password from environment
188
+ MCRCON_PASSWORD=secret minercon mc.example.com
189
+
190
+ # Save host/port for future sessions
191
+ minercon mc.example.com 25575 --password secret --save
192
+
193
+ # Next time, no arguments needed
194
+ minercon
195
+ ```
196
+
197
+ ---
198
+
199
+ ## Keyboard shortcuts
200
+
201
+ ### Navigation and completion
202
+
203
+ | Key | Action |
204
+ |---|---|
205
+ | `Tab` | Fetch / cycle to next suggestion |
206
+ | `Shift+Tab` | Cycle to previous suggestion |
207
+ | `Up` / `Ctrl+P` | Previous command in history (or move up in suggestion list) |
208
+ | `Down` / `Ctrl+N` | Next command in history (or move down in suggestion list) |
209
+ | `Ctrl+R` | Reverse search command history; press again to cycle to the next-older match |
210
+ | `Page Up` / `Page Down` | Page through suggestion list |
211
+ | `Esc` | Close suggestion list; if already closed, clear the line |
212
+ | `Enter` | Submit the current command |
213
+
214
+ ### Cursor movement
215
+
216
+ | Key | Action |
217
+ |---|---|
218
+ | `Left` / `Ctrl+B` | Move left one character |
219
+ | `Right` / `Ctrl+F` | Move right one character |
220
+ | `Ctrl+Left` / `Alt+B` | Move left one word |
221
+ | `Ctrl+Right` / `Alt+F` | Move right one word |
222
+ | `Home` / `Ctrl+A` | Move to start of line |
223
+ | `End` / `Ctrl+E` | Move to end of line |
224
+
225
+ ### Selection
226
+
227
+ | Key | Action |
228
+ |---|---|
229
+ | `Shift+Left` | Extend selection left |
230
+ | `Shift+Right` | Extend selection right |
231
+ | `Ctrl+Shift+Left` | Extend selection left by word |
232
+ | `Ctrl+Shift+Right` | Extend selection right by word |
233
+ | `Shift+Home` | Select to start of line |
234
+ | `Shift+End` | Select to end of line |
235
+
236
+ ### Editing
237
+
238
+ | Key | Action |
239
+ |---|---|
240
+ | `Backspace` | Delete character before cursor |
241
+ | `Delete` | Delete character after cursor |
242
+ | `Ctrl+T` | Transpose characters around cursor |
243
+ | `Ctrl+K` | Kill (cut) from cursor to end of line → kill ring |
244
+ | `Ctrl+U` | Kill from cursor to start of line → kill ring |
245
+ | `Ctrl+W` / `Alt+Backspace` | Kill word before cursor → kill ring |
246
+ | `Alt+D` | Kill word after cursor → kill ring |
247
+ | `Ctrl+Y` | Yank (paste) from kill ring |
248
+ | `Ctrl+X` | Cut selection → kill ring |
249
+ | `Ctrl+C` | Copy selection → kill ring (if text selected); otherwise echo `^C` and clear line |
250
+ | `Ctrl+V` | Paste from kill ring |
251
+
252
+ The kill ring is session-local in both the CLI and VS Code extension.
253
+
254
+ ### Terminal control
255
+
256
+ | Key | Action |
257
+ |---|---|
258
+ | `Ctrl+L` | Clear screen and redraw |
259
+ | `Ctrl+D` | On a non-empty line: delete character under cursor (forward delete). On an empty line: disconnect and exit |
260
+
261
+ ---
262
+
263
+ ## Built-in commands
264
+
265
+ These are handled by the terminal itself and never sent to the server. They
266
+ use a `.` prefix so there is no conflict with server commands (which use `/`).
267
+
268
+ | Command | Description |
269
+ |---|---|
270
+ | `.help` | Show this list of built-in commands and keyboard shortcuts |
271
+ | `.clear` | Clear the terminal screen |
272
+ | `.history` | Show command history |
273
+ | `.reconnect` | Manually reconnect to the server |
274
+ | `.disconnect` | Disconnect (stays open; use `Ctrl+D` to also exit) |
275
+ | `.reload-commands` | Force a fresh crawl of the server's command tree (local mode only) |
276
+ | `.clear-cache` | Delete the cached command tree for this server (local mode only) |
277
+ | `.cache-info` | Show the age and location of the cached command tree |
278
+
279
+ Everything else — including any `/command` — is sent directly to the server as
280
+ an RCON command.
281
+
282
+ ---
283
+
284
+ ## Tab completion modes
285
+
286
+ The terminal detects which mode to use automatically when it first connects.
287
+
288
+ **Plugin mode** (preferred) — requires the [Paper TabComplete](paper-plugin/)
289
+ or [Spigot TabComplete](spigot-plugin/) plugin (or the
290
+ [Fabric TabComplete](fabric-mod/) mod) installed on your server. Completions
291
+ are fetched live from the server as you type, identical to in-game tab
292
+ completion.
293
+
294
+ **Local mode** (fallback) — the terminal fetches and parses your server's
295
+ `/help` output once, builds a command tree, and caches it to disk. Subsequent
296
+ connections load from cache (nearly instant). Use `.reload-commands` to
297
+ refresh after a server update.
298
+
299
+ Cache location:
300
+ - VS Code: `<extension global storage>/command-cache/<host>_<port>.json`
301
+ - CLI: `~/.config/minercon/command-cache/<host>_<port>.json`
302
+
303
+ ---
304
+
305
+ ## Building and installing the TabComplete plugins
306
+
307
+ ### Paper
308
+
309
+ The Paper plugin lives in [`paper-plugin/`](paper-plugin/). It requires Java 21
310
+ and a Paper 1.21+ server, and uses
311
+ [paperweight-userdev](https://docs.papermc.io/paper/dev/userdev/) for direct
312
+ typed access to Paper's Brigadier command dispatcher (no reflection).
313
+
314
+ **Build:**
315
+
316
+ ```sh
317
+ cd paper-plugin
318
+ ./gradlew build
319
+ ```
320
+
321
+ The built jar ends up at `paper-plugin/build/libs/paper-tabcomplete-1.0.0.jar`.
322
+
323
+ ### Spigot
324
+
325
+ The Spigot plugin lives in [`spigot-plugin/`](spigot-plugin/). It requires
326
+ Java 21 and a Spigot 1.21+ server.
327
+
328
+ **Build:**
329
+
330
+ ```sh
331
+ cd spigot-plugin
332
+ ./gradlew build
333
+ ```
334
+
335
+ The built jar ends up at `spigot-plugin/build/libs/spigot-tabcomplete-1.0.0.jar`.
336
+
337
+ ### Install (both)
338
+
339
+ Drop the jar into your server's `plugins/` directory and restart. No
340
+ configuration is needed — the plugin activates automatically and exposes the
341
+ `/tabcomplete` and `/cmdusage` RCON commands that this client uses.
342
+
343
+ ---
344
+
345
+ ## Troubleshooting
346
+
347
+ **"Connection refused"** — verify `enable-rcon=true` in `server.properties`
348
+ and that the RCON port is not blocked by a firewall.
349
+
350
+ **"Authentication failed"** — double-check `rcon.password` in
351
+ `server.properties`. Passwords are case-sensitive.
352
+
353
+ **Autocomplete not working in local mode**
354
+ 1. `.clear-cache` to discard the old tree
355
+ 2. `.reload-commands` to re-crawl
356
+ 3. Check that your account has permission to run `/help` on the server
357
+ 4. In VS Code, check View → Output → Minercon for crawl diagnostics
358
+
359
+ **Truncated responses** — this was a bug in versions before v2.0, which used
360
+ an external library with a 4096-byte limit. The current implementation has no
361
+ such limit.
362
+
363
+ **Suggestion display looks wrong** — try `.clear` to redraw the screen. If
364
+ the issue persists in the CLI, ensure your terminal reports correct dimensions
365
+ (`echo $COLUMNS $LINES`).
366
+
367
+ ---
368
+
369
+ ## Contributing
370
+
371
+ ```sh
372
+ git clone https://github.com/xton/minercon.git
373
+ cd minercon
374
+ npm install
375
+ npm run compile
376
+ npm test
377
+ ```
378
+
379
+ The test suite runs inside VS Code's extension host. Run it with `npm test`; no
380
+ live server is required — the RCON layer has a record/replay fixture harness.
381
+
382
+ See [CHANGELOG.md](CHANGELOG.md) for version history and
383
+ [CONTRIBUTING.md](CONTRIBUTING.md) for development guidelines.
384
+
385
+ ---
386
+
387
+ ## Acknowledgements
388
+
389
+ Minercon (formerly "Minecraft RCON Terminal") began as a fork of
390
+ [jaketcooper/Minecraft-rcon](https://github.com/jaketcooper/Minecraft-rcon),
391
+ which provided the initial RCON protocol implementation and VS Code extension
392
+ scaffold, help-based tab completion, interactive terminal experience, line editing.
393
+ Plugin-mode tab-completion, standalone CLI, history search, lots of testing, loads
394
+ of polish, countless fixes, and the new name were developed from there with significant
395
+ help from [Claude](https://claude.ai).
396
+
397
+ ---
398
+
399
+ ## License
400
+
401
+ MIT — see [LICENSE](LICENSE).
Binary file
package/out/ansi.js ADDED
@@ -0,0 +1,123 @@
1
+ "use strict";
2
+ // src/ansi.ts
3
+ //
4
+ // Named ANSI SGR (Select Graphic Rendition) escape codes for terminal
5
+ // output, plus small `style`/color helpers that wrap text and reset
6
+ // afterward. Centralizes the raw `\x1b[...m` literals previously scattered
7
+ // across rconSession.ts, displaySuggestion.ts, lineEditor.ts,
8
+ // rconConnectionManager.ts, and cli.ts.
9
+ //
10
+ // Also home to `formatMinecraftColors`/`stripColors`, which translate the
11
+ // server-controlled Minecraft `§`-color-code alphabet to/from ANSI - a
12
+ // distinct input alphabet from the literals above, but the same output
13
+ // format, so it lives alongside them rather than in
14
+ // commandTreeParsingBrigadier.ts.
15
+ Object.defineProperty(exports, "__esModule", { value: true });
16
+ exports.hidden = exports.reverse = exports.boldBrightWhite = exports.boldCyan = exports.boldGreen = exports.boldRed = exports.brightYellow = exports.dim = exports.gray = exports.cyan = exports.yellow = exports.green = exports.red = exports.BOLD_BRIGHT_WHITE = exports.BOLD_CYAN = exports.BOLD_GREEN = exports.BOLD_RED = exports.BRIGHT_YELLOW = exports.GRAY = exports.CYAN = exports.YELLOW = exports.GREEN = exports.RED = exports.HIDDEN = exports.REVERSE_OFF = exports.REVERSE = exports.DIM = exports.RESET = void 0;
17
+ exports.style = style;
18
+ exports.formatMinecraftColors = formatMinecraftColors;
19
+ exports.stripColors = stripColors;
20
+ exports.stripAnsi = stripAnsi;
21
+ exports.RESET = '\x1b[0m';
22
+ exports.DIM = '\x1b[2m';
23
+ exports.REVERSE = '\x1b[7m';
24
+ exports.REVERSE_OFF = '\x1b[27m';
25
+ exports.HIDDEN = '\x1b[8m';
26
+ exports.RED = '\x1b[31m';
27
+ exports.GREEN = '\x1b[32m';
28
+ exports.YELLOW = '\x1b[33m';
29
+ exports.CYAN = '\x1b[36m';
30
+ exports.GRAY = '\x1b[90m';
31
+ exports.BRIGHT_YELLOW = '\x1b[93m';
32
+ exports.BOLD_RED = '\x1b[1;31m';
33
+ exports.BOLD_GREEN = '\x1b[1;32m';
34
+ exports.BOLD_CYAN = '\x1b[1;36m';
35
+ exports.BOLD_BRIGHT_WHITE = '\x1b[1;97m';
36
+ /** Wraps `text` in `code`, resetting afterward. */
37
+ function style(code, text) {
38
+ return `${code}${text}${exports.RESET}`;
39
+ }
40
+ const red = (text) => style(exports.RED, text);
41
+ exports.red = red;
42
+ const green = (text) => style(exports.GREEN, text);
43
+ exports.green = green;
44
+ const yellow = (text) => style(exports.YELLOW, text);
45
+ exports.yellow = yellow;
46
+ const cyan = (text) => style(exports.CYAN, text);
47
+ exports.cyan = cyan;
48
+ const gray = (text) => style(exports.GRAY, text);
49
+ exports.gray = gray;
50
+ const dim = (text) => style(exports.DIM, text);
51
+ exports.dim = dim;
52
+ const brightYellow = (text) => style(exports.BRIGHT_YELLOW, text);
53
+ exports.brightYellow = brightYellow;
54
+ const boldRed = (text) => style(exports.BOLD_RED, text);
55
+ exports.boldRed = boldRed;
56
+ const boldGreen = (text) => style(exports.BOLD_GREEN, text);
57
+ exports.boldGreen = boldGreen;
58
+ const boldCyan = (text) => style(exports.BOLD_CYAN, text);
59
+ exports.boldCyan = boldCyan;
60
+ const boldBrightWhite = (text) => style(exports.BOLD_BRIGHT_WHITE, text);
61
+ exports.boldBrightWhite = boldBrightWhite;
62
+ const reverse = (text) => style(exports.REVERSE, text);
63
+ exports.reverse = reverse;
64
+ const hidden = (text) => style(exports.HIDDEN, text);
65
+ exports.hidden = hidden;
66
+ // Minecraft `§`-color codes to ANSI escape sequences
67
+ const MINECRAFT_COLOR_MAP = {
68
+ '§0': '\x1b[30m', // Black
69
+ '§1': '\x1b[34m', // Dark Blue
70
+ '§2': '\x1b[32m', // Dark Green
71
+ '§3': '\x1b[36m', // Dark Aqua
72
+ '§4': '\x1b[31m', // Dark Red
73
+ '§5': '\x1b[35m', // Dark Purple
74
+ '§6': '\x1b[33m', // Gold
75
+ '§7': '\x1b[37m', // Gray
76
+ '§8': '\x1b[90m', // Dark Gray
77
+ '§9': '\x1b[94m', // Blue
78
+ '§a': '\x1b[92m', // Green
79
+ '§b': '\x1b[96m', // Aqua
80
+ '§c': '\x1b[91m', // Red
81
+ '§d': '\x1b[95m', // Light Purple
82
+ '§e': '\x1b[93m', // Yellow
83
+ '§f': '\x1b[97m', // White
84
+ '§r': exports.RESET, // Reset
85
+ '§l': '\x1b[1m', // Bold
86
+ '§o': '\x1b[3m', // Italic
87
+ '§n': '\x1b[4m', // Underline
88
+ '§m': '\x1b[9m', // Strikethrough
89
+ '§k': '\x1b[5m', // Obfuscated (blinking)
90
+ };
91
+ // Matches any single `§X` color/format code; the replacer looks each up in
92
+ // MINECRAFT_COLOR_MAP. The character class covers exactly that map's keys.
93
+ const MINECRAFT_COLOR_PATTERN = /§[0-9a-fklmnor]/g;
94
+ /**
95
+ * Convert Minecraft `§`-color codes to ANSI escape sequences.
96
+ */
97
+ function formatMinecraftColors(text) {
98
+ // Collapse the `§` UTF-8 mojibake of the section sign first (same encodings
99
+ // stripColors handles) — otherwise the orphaned `Â` is left in the colored
100
+ // output once the `§x` after it is converted.
101
+ let result = text.replace(/§/g, '§').replace(MINECRAFT_COLOR_PATTERN, code => MINECRAFT_COLOR_MAP[code] ?? '');
102
+ if (!result.endsWith(exports.RESET)) {
103
+ result += exports.RESET;
104
+ }
105
+ return result;
106
+ }
107
+ /**
108
+ * Remove Minecraft `§`-color codes, e.g. before parsing.
109
+ */
110
+ function stripColors(text) {
111
+ // Handle both § and § encodings (UTF-8 issues)
112
+ return text.replace(/[§Â]§[0-9a-fklmnor]/g, '')
113
+ .replace(/§[0-9a-fklmnor]/g, '');
114
+ }
115
+ /**
116
+ * Remove ANSI SGR (color/style) escape sequences — e.g. to measure a styled
117
+ * string's *visible* width. Distinct from `stripColors`, which removes the
118
+ * Minecraft `§`-code alphabet rather than the ANSI escapes those map to.
119
+ */
120
+ function stripAnsi(text) {
121
+ return text.replace(/\x1b\[[0-9;]*m/g, '');
122
+ }
123
+ //# sourceMappingURL=ansi.js.map
@@ -0,0 +1,43 @@
1
+ "use strict";
2
+ // src/argumentHint.ts
3
+ //
4
+ // Pure formatting for the "argument hint" display: given a command's usage
5
+ // string (e.g. "gamemode <mode> [<target>]") and the line the user has typed
6
+ // so far, work out which argument position they're at and which token in the
7
+ // usage string corresponds to it (so it can be highlighted).
8
+ //
9
+ // This is presentation logic, not decision logic — it has no notion of
10
+ // fetching, timing, or staleness — so it lives apart from completionEngine's
11
+ // state machine, as its own pure, independently-testable function.
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ exports.formatArgumentHint = formatArgumentHint;
14
+ const ARGUMENT_TOKEN_PATTERN = /(<[^>]+>|\[[^\]]+\]|\([^)]+\))/g;
15
+ /** Returns null when there's no usage text to show anything for. */
16
+ function formatArgumentHint(usage, line) {
17
+ if (!usage) {
18
+ return null;
19
+ }
20
+ const tokens = usage.match(ARGUMENT_TOKEN_PATTERN) || [];
21
+ // The literal words before the first argument token are the command path —
22
+ // derived straight from the usage string so we don't need a separate
23
+ // "commandPath" concept threaded in from wherever the usage came from.
24
+ const firstTokenStart = usage.search(ARGUMENT_TOKEN_PATTERN);
25
+ const literalPrefix = (firstTokenStart >= 0 ? usage.slice(0, firstTokenStart) : usage).trim();
26
+ const commandPrefixWordCount = literalPrefix.length > 0 ? literalPrefix.split(/\s+/).length : 0;
27
+ const commandPrefixText = '/' + literalPrefix;
28
+ const parts = line.trim().split(' ').filter(p => p.length > 0);
29
+ const hasTrailingSpace = line.endsWith(' ');
30
+ const argumentCount = Math.max(0, parts.length - commandPrefixWordCount);
31
+ let currentArgIndex;
32
+ if (argumentCount === 0 && !hasTrailingSpace) {
33
+ currentArgIndex = -1; // still typing the command/subcommand itself
34
+ }
35
+ else if (hasTrailingSpace) {
36
+ currentArgIndex = argumentCount; // ready for the next argument
37
+ }
38
+ else {
39
+ currentArgIndex = argumentCount - 1; // currently typing this argument
40
+ }
41
+ return { commandPrefixText, tokens, currentArgIndex };
42
+ }
43
+ //# sourceMappingURL=argumentHint.js.map
@@ -0,0 +1,62 @@
1
+ "use strict";
2
+ // src/bukkitHelpParsing.ts
3
+ //
4
+ // Pure parsing of Bukkit's hand-written `/help <command>` pages - a
5
+ // "§e--------- §fHelp: /<cmd> ----...§e" banner line followed by
6
+ // `Description:`/`Usage:`/`Aliases:` lines. This is a different grammar from
7
+ // the flat Brigadier `/cmd <args>` blobs `helpTextParsing.ts` handles
8
+ // (`minecraft:help`, vanilla's plain `help`): on a server where the
9
+ // `minecraft:` namespace is supported (Paper/Spigot), `help <path>` is
10
+ // *always* one of these pages, for every command - vanilla-backed or
11
+ // Bukkit-added alike - so no shape-sniffing is needed to decide which parser
12
+ // applies, only `LocalCommandTree.supportsMinecraftNamespace`.
13
+ //
14
+ // No state, no IO — every export here is a deterministic function of its
15
+ // arguments.
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ exports.extractBukkitUsageLines = extractBukkitUsageLines;
18
+ exports.extractBukkitAliases = extractBukkitAliases;
19
+ const ansi_1 = require("./ansi");
20
+ /**
21
+ * Extract the `Usage: ...` line(s) from a Bukkit-style `/help <command>`
22
+ * response (e.g. "Description: ...\nUsage: /version [plugin name]\nAliases:
23
+ * ..."), normalized so each reads as `<commandPath> ...` for `parseHelpLines`.
24
+ * Returns `[]` if there's no Usage line, or if its content is just the bare
25
+ * command name with nothing after it — the generic response Bukkit gives for
26
+ * Brigadier-backed (vanilla) commands ("Description: A Mojang provided
27
+ * command.\nUsage: <name>"), which carries no argument info.
28
+ */
29
+ function extractBukkitUsageLines(helpText, commandPath) {
30
+ const lines = (0, ansi_1.stripColors)(helpText).split('\n').map(line => line.trim());
31
+ const usageIndex = lines.findIndex(line => /^Usage:\s*/i.test(line));
32
+ if (usageIndex === -1) {
33
+ return [];
34
+ }
35
+ const result = [lines[usageIndex].replace(/^Usage:\s*/i, '')];
36
+ for (let i = usageIndex + 1; i < lines.length; i++) {
37
+ const line = lines[i];
38
+ if (!line || /^[A-Za-z][A-Za-z ]*:/.test(line) || line.startsWith('---')) {
39
+ break;
40
+ }
41
+ result.push(line);
42
+ }
43
+ const normalizedPath = commandPath.toLowerCase();
44
+ return result.filter(line => line.replace(/^\//, '').toLowerCase() !== normalizedPath);
45
+ }
46
+ /**
47
+ * Extract alias names from a Bukkit-style `/help <command>` response's
48
+ * `Aliases: a, b, c` line (e.g. "Description: ...\nUsage: ...\nAliases: ver,
49
+ * about"). Returns `[]` if there's no Aliases line.
50
+ */
51
+ function extractBukkitAliases(helpText) {
52
+ const lines = (0, ansi_1.stripColors)(helpText).split('\n').map(line => line.trim());
53
+ const aliasesLine = lines.find(line => /^Aliases:\s*/i.test(line));
54
+ if (!aliasesLine) {
55
+ return [];
56
+ }
57
+ return aliasesLine.replace(/^Aliases:\s*/i, '')
58
+ .split(',')
59
+ .map(alias => alias.trim())
60
+ .filter(alias => alias.length > 0);
61
+ }
62
+ //# sourceMappingURL=bukkitHelpParsing.js.map