fix(tui): surfaced skill commands in slash menu
Prioritized /skill:* entries for the empty slash autocomplete query so user skills appear in the initial popup instead of below all built-ins. Added autocomplete regression coverage for empty slash query ordering. Fixes #2875
This commit is contained in:
@@ -6,6 +6,10 @@
|
||||
|
||||
- Coalesced byte-adjacent SGR sequences in emitted lines into a single `CSI … m`. The component tree styles each span as `<set>text<reset>`, so adjacent spans emit runs of back-to-back SGR sequences (e.g. a `CSI 39 m` fg-reset immediately followed by the next span's `CSI 38;2;r;g;b m`); merging the run is behavior-preserving because SGR parameters apply left-to-right regardless of framing. On a real transcript this drops ~30-40% of all SGR sequences, cutting the per-frame byte volume and SGR-dispatch count a slow terminal engine (e.g. xterm.js/WebGL under a large viewport) must process. Each emitted sequence is capped at 16 parameter tokens so a long adjacent run is split across several valid CSIs instead of overflowing a terminal's parameter buffer (xterm.js caps at 32 and silently truncates, corrupting colors). A run is never extended past a parameter list that ends in an incomplete semicolon-form extended color (`38/48/58;2` missing a channel or `;5` missing the index), so a following code can't be absorbed as the missing component. Disable with `PI_NO_SGR_COALESCE=1`.
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed empty `/` autocomplete burying user skill commands below every built-in command, so installed skills appear in the initial slash popup ([#2875](https://github.com/can1357/oh-my-pi/issues/2875)).
|
||||
|
||||
## [16.0.3] - 2026-06-16
|
||||
|
||||
### Added
|
||||
|
||||
@@ -249,7 +249,9 @@ function buildSlashCommandCompletions(commands: CommandEntry[], lowerPrefix: str
|
||||
const fullDesc = hint ? (desc ? `${hint} — ${desc}` : hint) : desc;
|
||||
const candidates: Array<AutocompleteItem & { score: number }> = [];
|
||||
|
||||
const nameScore = scoreCommandTextMatch(lowerPrefix, name.toLowerCase());
|
||||
const isSkillCommand = name.startsWith("skill:");
|
||||
const nameScore =
|
||||
lowerPrefix.length === 0 && isSkillCommand ? 950 : scoreCommandTextMatch(lowerPrefix, name.toLowerCase());
|
||||
const lowerDesc = desc.toLowerCase();
|
||||
const descScore =
|
||||
lowerDesc && fuzzyMatch(lowerPrefix, lowerDesc) ? fuzzyScore(lowerPrefix, lowerDesc) * 0.5 : 0;
|
||||
|
||||
@@ -61,6 +61,22 @@ describe("CombinedAutocompleteProvider", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("slash commands", () => {
|
||||
it("surfaces skill commands before built-ins for an empty slash query", async () => {
|
||||
const provider = new CombinedAutocompleteProvider(
|
||||
[
|
||||
{ name: "settings", description: "Open settings" },
|
||||
{ name: "model", description: "Switch model" },
|
||||
{ name: "skill:reviewer", description: "Review code" },
|
||||
],
|
||||
"/tmp",
|
||||
);
|
||||
|
||||
const result = await provider.getSuggestions(["/"], 0, 1);
|
||||
|
||||
expect(result?.items.map(item => item.value).slice(0, 3)).toEqual(["skill:reviewer", "settings", "model"]);
|
||||
});
|
||||
});
|
||||
describe("applyCompletion", () => {
|
||||
it("replaces the live slash command prefix when rendered suggestions are stale", () => {
|
||||
const provider = new CombinedAutocompleteProvider([], "/tmp");
|
||||
|
||||
Reference in New Issue
Block a user