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.
- package/CHANGELOG.md +439 -0
- package/LICENSE +22 -0
- package/README.md +401 -0
- package/images/icon.png +0 -0
- package/out/ansi.js +123 -0
- package/out/argumentHint.js +43 -0
- package/out/bukkitHelpParsing.js +62 -0
- package/out/cli.js +253 -0
- package/out/cliConfig.js +141 -0
- package/out/commandLine.js +28 -0
- package/out/commandSuggestions.js +202 -0
- package/out/commandTree.js +46 -0
- package/out/commandTreeCache.js +171 -0
- package/out/commandTreeCrawler.js +583 -0
- package/out/commandTreeParsingBrigadier.js +426 -0
- package/out/commandTreeParsingBukkit.js +116 -0
- package/out/commandTreeSuggestions.js +142 -0
- package/out/completionBackend.js +94 -0
- package/out/completionEngine.js +376 -0
- package/out/completionQueries.js +86 -0
- package/out/completionsBackend.js +97 -0
- package/out/connectionManager.js +209 -0
- package/out/displayArgumentHint.js +43 -0
- package/out/displayCommandTree.js +115 -0
- package/out/displaySuggestion.js +282 -0
- package/out/extension.js +190 -0
- package/out/helpTextParsing.js +445 -0
- package/out/historySearch.js +46 -0
- package/out/historyStore.js +126 -0
- package/out/lineEditor.js +525 -0
- package/out/localCommandTree.js +541 -0
- package/out/logger.js +14 -0
- package/out/minercon +253 -0
- package/out/pager.js +168 -0
- package/out/pagination.js +142 -0
- package/out/rconClient.js +97 -0
- package/out/rconConnectionManager.js +238 -0
- package/out/rconProtocol.js +421 -0
- package/out/rconSession.js +920 -0
- package/out/rconTerminal.js +80 -0
- package/out/suggestionDisplay.js +286 -0
- package/out/terminalOutput.js +110 -0
- package/out/unpaginate.js +30 -0
- 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
|
+

|
|
8
|
+

|
|
9
|
+

|
|
10
|
+
|
|
11
|
+
> A heavy fork of "Minecraft RCON Terminal"
|
|
12
|
+
|
|
13
|
+

|
|
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).
|
package/images/icon.png
ADDED
|
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
|