diff --git a/docs/superpowers/specs/2026-05-17-console-command-autocomplete-design.md b/docs/superpowers/specs/2026-05-17-console-command-autocomplete-design.md new file mode 100644 index 0000000..9eed7bc --- /dev/null +++ b/docs/superpowers/specs/2026-05-17-console-command-autocomplete-design.md @@ -0,0 +1,122 @@ +# Console Command Autocomplete — Design + +**Date:** 2026-05-17 +**Status:** Approved for implementation planning + +## Context + +The L4D2 web admin already has a config editor (CodeMirror 6 based) that offers autocomplete for Source-engine console commands and cvars, sourced from a JSON vocab file (`l4d2web/l4d2web/static/data/srccfg-vocab.json`, 671 commands + cvars with descriptions). The same vocabulary is useful at the **runtime console** input on `server_detail.html`, where admins type commands against a live server — but no autocomplete exists there today. Users have to remember exact command names, leading to typos and trial-and-error against a production server. + +Goal: add autocomplete to the runtime console input, reusing the editor's ranking logic where reuse is cheap, without modifying the editor's behavior and without colliding with the existing `console-history.js` ArrowUp/Down history recall. + +## Scope + +- **In scope:** dropdown autocomplete on the server-detail console input, sharing the editor's ranking algorithm and the existing `srccfg-vocab.json` data file. +- **Out of scope:** argument-value completion (player names for `kick`, map names for `changelevel`, etc. — needs runtime data); fuzzy/typo-tolerant matching; custom per-game vocabs (the API accepts a URL so the door is open, but only `srccfg-vocab.json` ships); replacing CodeMirror's built-in dropdown in the editor. + +## Key Decisions (from brainstorming) + +| # | Decision | Rationale | +|---|---|---| +| 1 | **Level A reuse:** extract ranker into a shared module; build a small vanilla dropdown for the console. Editor keeps CodeMirror's built-in dropdown. | Shares the product judgment (ranking algorithm) without coupling the console to CodeMirror. ~10-line shared brain + ~80-line vanilla dropdown. | +| 2 | **Fetch vocab on console input focus, once per page load.** | Doesn't compete with page load. Browser cache makes subsequent visits free. By the time the user finishes typing the first character, fetch is usually done. | +| 3 | **Tab / Shift+Tab cycle the dropdown; Esc dismisses; Enter submits the input as-typed; ArrowUp/Down untouched (history keeps them).** | ArrowUp/Down already belongs to `console-history.js`. Autocomplete cannot ever *change* the submitted command — safety on a live game server. Mouse + Tab covers selection. | +| 4 | **Dropdown rows show name + description**, mirroring the editor's format. | Same visual affordance as editor → muscle memory transfers. Vocab JSON already carries `desc`. | +| 5 | **First-token only**: dropdown hides as soon as the user types a space. | Vocab only knows command names, not argument grammars. Quiet-when-uncertain beats confident-and-wrong. | + +## Architecture + +Three moving parts: + +1. **Extract the ranker.** Move pure ranking logic out of `l4d2web/scripts/editor-src/autocomplete.js` into new module `l4d2web/scripts/editor-src/vocab-rank.js`. Function signature: `rankVocab(query: string, vocab: {cvars, commands}) → Array<{name, desc, kind}>`. No CodeMirror dependency. `autocomplete.js` re-imports it; the editor build keeps working unchanged. + +2. **Console autocomplete module.** New file `l4d2web/l4d2web/static/js/console-autocomplete.js`. Vanilla JS, no framework. Imports the ranker (delivery details — separate static script, or compiled into the editor bundle output — to be resolved in the implementation plan). Exposes one entry point: `attachAutocomplete(inputEl, vocabUrl)`. + +3. **Wire-up on server-detail.** A new `