Files
llmx/codex-cli/tests/slash-commands.test.ts
Thomas 081786eaa6 feat: add /command autocomplete (#317)
Add interactive slash‑command autocomplete & navigation in chat input

    Description
This PR enhances the chat input component by adding first‑class support
for slash commands (/help, /clear, /compact, etc.)
    with:

* **Live filtering:** As soon as the user types leading `/`, a list of
matching commands is shown below the prompt.
* **Arrow‑key navigation:** Up/Down arrows cycle through suggestions.
* **Enter to autocomplete:** Pressing Enter on a partial command will
fill it (without submitting) so you can add
    arguments or simply press Enter again to execute.
* **Type‑safe registry:** A new `slash‑commands.ts` file declares all
supported commands in one place, along with
    TypeScript types to prevent drift.
* **Validation:** Only registered commands will ever autocomplete or be
suggested; unknown single‑word slash inputs still
    show an “Invalid command” system message.
        * **Automated tests:**
            * Unit tests for the command registry and prefix filtering

            * Existing tests continue passing with no regressions

    Motivation
Slash commands provide a quick, discoverable way to control the agent
(clearing history, compacting context, opening overlays,
etc.). Before, users had to memorize the exact command or rely on the
generic /help list—autocomplete makes them far more
    accessible and reduces typos.

    Changes

* `src/utils/slash‑commands.ts` – defines `SlashCommand` and exports a
flat list of supported commands + descriptions
        * `terminal‑chat‑input.tsx`
            * Import and type the command registry

* Render filtered suggestions under the prompt when input starts with
`/`

* Hook into `useInput` to handle Up/Down and Enter for selection & fill

* Flag to swallow the first Enter (autocomplete) and only submit on the
next
* Updated tests in `tests/slash‑commands.test.ts` to cover registry
contents and filtering logic
        * Removed old JS version and fixed stray `@ts‑expect‑error`

    How to test locally

        1. Type `/` in the prompt—you should see matching commands.
2. Use arrows to move the highlight, press Enter to fill, then Enter
again to execute.
3. Run the full test suite (`npm test`) to verify no regressions.

    Notes

* Future work could include fuzzy matching, paging long lists, or more
visual styling.
* This change is purely additive and does not affect non‑slash inputs or
existing slash handlers.

---------

Co-authored-by: Fouad Matin <169186268+fouad-openai@users.noreply.github.com>
Co-authored-by: Thibault Sottiaux <tibo@openai.com>
2025-04-19 07:25:46 -07:00

39 lines
1.3 KiB
TypeScript

import { test, expect } from "vitest";
import { SLASH_COMMANDS, type SlashCommand } from "../src/utils/slash-commands";
test("SLASH_COMMANDS includes expected commands", () => {
const commands = SLASH_COMMANDS.map((c: SlashCommand) => c.command);
expect(commands).toContain("/clear");
expect(commands).toContain("/compact");
expect(commands).toContain("/history");
expect(commands).toContain("/help");
expect(commands).toContain("/model");
expect(commands).toContain("/approval");
expect(commands).toContain("/clearhistory");
});
test("filters slash commands by prefix", () => {
const prefix = "/c";
const filtered = SLASH_COMMANDS.filter((c: SlashCommand) =>
c.command.startsWith(prefix),
);
const names = filtered.map((c: SlashCommand) => c.command);
expect(names).toEqual(
expect.arrayContaining(["/clear", "/clearhistory", "/compact"]),
);
expect(names).not.toEqual(
expect.arrayContaining(["/history", "/help", "/model", "/approval"]),
);
const emptyPrefixFiltered = SLASH_COMMANDS.filter((c: SlashCommand) =>
c.command.startsWith(""),
);
const emptyPrefixNames = emptyPrefixFiltered.map(
(c: SlashCommand) => c.command,
);
expect(emptyPrefixNames).toEqual(
expect.arrayContaining(SLASH_COMMANDS.map((c: SlashCommand) => c.command)),
);
expect(emptyPrefixNames).toHaveLength(SLASH_COMMANDS.length);
});