diff --git a/CHANGELOG.md b/CHANGELOG.md index 23e1df1f9..b29083e03 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,11 @@ ## Unreleased +- Expanded the TUI slash command overlay catalog to include 67 commands across + 14 groups, aligned with the specification command reference for session, + persona, scope, plan, project, registry/config, context, and utility flows. + Added Behave coverage for command and group cardinality plus representative + command presence checks. (#1002) - Strengthened WF02 trusted-profile integration coverage for automated test generation. The helper now validates and incorporates mocked provider output (instead of discarding it), asserts all WF02 invariant conventions (test-only diff --git a/features/steps/tui_slash_command_catalog_steps.py b/features/steps/tui_slash_command_catalog_steps.py new file mode 100644 index 000000000..fb7c408a5 --- /dev/null +++ b/features/steps/tui_slash_command_catalog_steps.py @@ -0,0 +1,28 @@ +"""Step definitions for TUI slash command catalog coverage.""" + +from __future__ import annotations + +from behave import given, then + + +@given("the TUI slash command catalog module is loaded") +def step_catalog_loaded(context): + from cleveragents.tui.slash_catalog import slash_command_groups, slash_command_names + + context._slash_command_names = slash_command_names() + context._slash_command_groups = slash_command_groups() + + +@then("the slash command catalog should contain at least {minimum:d} commands") +def step_catalog_command_count(context, minimum): + assert len(context._slash_command_names) >= minimum + + +@then("the slash command catalog should contain exactly {expected:d} groups") +def step_catalog_group_count(context, expected): + assert len(context._slash_command_groups) == expected + + +@then('the slash command catalog should include "{command}"') +def step_catalog_contains_command(context, command): + assert command in context._slash_command_names diff --git a/features/tui_slash_command_catalog.feature b/features/tui_slash_command_catalog.feature new file mode 100644 index 000000000..cd61bba5d --- /dev/null +++ b/features/tui_slash_command_catalog.feature @@ -0,0 +1,13 @@ +Feature: TUI Slash Command Catalog + Scenario: Slash command catalog enumerates 60+ commands across 14 groups + Given the TUI slash command catalog module is loaded + Then the slash command catalog should contain at least 60 commands + And the slash command catalog should contain exactly 14 groups + + Scenario: Slash command catalog includes representative commands + Given the TUI slash command catalog module is loaded + Then the slash command catalog should include "session:create" + And the slash command catalog should include "plan:rollback" + And the slash command catalog should include "project:context:show" + And the slash command catalog should include "profile:show" + And the slash command catalog should include "settings" diff --git a/src/cleveragents/tui/app.py b/src/cleveragents/tui/app.py index 214a058a1..271c908ab 100644 --- a/src/cleveragents/tui/app.py +++ b/src/cleveragents/tui/app.py @@ -10,6 +10,7 @@ from typing import TYPE_CHECKING, Any, ClassVar, Protocol from cleveragents.tui.input.modes import InputMode, InputModeRouter from cleveragents.tui.input.reference_parser import suggestions from cleveragents.tui.persona.state import PersonaState +from cleveragents.tui.slash_catalog import slash_command_names from cleveragents.tui.widgets.persona_bar import PersonaBar from cleveragents.tui.widgets.prompt import PromptInput from cleveragents.tui.widgets.reference_picker import ReferencePickerOverlay @@ -116,9 +117,7 @@ if _TEXTUAL_AVAILABLE: ref_picker = self.query_one("#reference-picker", ReferencePickerOverlay) ref_picker.set_suggestions("", []) slash = self.query_one("#slash-overlay", SlashCommandOverlay) - slash.set_commands( - "", ["persona list", "persona set", "session show", "help"] - ) + slash.set_commands("", slash_command_names()) def action_help(self) -> None: conversation = self.query_one("#conversation", _Static) diff --git a/src/cleveragents/tui/slash_catalog.py b/src/cleveragents/tui/slash_catalog.py new file mode 100644 index 000000000..df65533a1 --- /dev/null +++ b/src/cleveragents/tui/slash_catalog.py @@ -0,0 +1,98 @@ +"""Slash command catalog for TUI command overlay.""" + +from __future__ import annotations + +from dataclasses import dataclass + + +@dataclass(frozen=True, slots=True) +class SlashCommandSpec: + """Single slash command descriptor.""" + + command: str + group: str + description: str + + +SLASH_COMMAND_SPECS: tuple[SlashCommandSpec, ...] = ( + SlashCommandSpec("session:create", "Session", "Create a new session tab"), + SlashCommandSpec("session:list", "Session", "Display all sessions"), + SlashCommandSpec("session:show", "Session", "Show session details"), + SlashCommandSpec("session:switch", "Session", "Switch to a session"), + SlashCommandSpec("session:close", "Session", "Close the current session"), + SlashCommandSpec("session:delete", "Session", "Delete a saved session"), + SlashCommandSpec("session:rename", "Session", "Rename current session"), + SlashCommandSpec("session:export", "Session", "Export session to JSON"), + SlashCommandSpec("session:import", "Session", "Import session from JSON"), + SlashCommandSpec("persona:list", "Persona", "Display all personas"), + SlashCommandSpec("persona:set", "Persona", "Switch active persona"), + SlashCommandSpec("persona:create", "Persona", "Create a persona"), + SlashCommandSpec("persona:edit", "Persona", "Edit a persona"), + SlashCommandSpec("persona:delete", "Persona", "Delete a persona"), + SlashCommandSpec("persona:export", "Persona", "Export persona YAML"), + SlashCommandSpec("persona:import", "Persona", "Import persona YAML"), + SlashCommandSpec("scope:add", "Scope", "Add scope reference"), + SlashCommandSpec("scope:remove", "Scope", "Remove scope reference"), + SlashCommandSpec("scope:clear", "Scope", "Clear session scope additions"), + SlashCommandSpec("scope:show", "Scope", "Show effective scope"), + SlashCommandSpec("plan:use", "Plan", "Start a new plan"), + SlashCommandSpec("plan:list", "Plan", "List plans"), + SlashCommandSpec("plan:status", "Plan", "Show plan status"), + SlashCommandSpec("plan:tree", "Plan", "Show decision tree"), + SlashCommandSpec("plan:execute", "Plan", "Execute a plan"), + SlashCommandSpec("plan:apply", "Plan", "Apply a completed plan"), + SlashCommandSpec("plan:cancel", "Plan", "Cancel a plan"), + SlashCommandSpec("plan:diff", "Plan", "Show plan diff"), + SlashCommandSpec("plan:correct", "Plan", "Correct a decision"), + SlashCommandSpec("plan:resume", "Plan", "Resume a plan"), + SlashCommandSpec("plan:revert", "Plan", "Revert plan state"), + SlashCommandSpec("plan:rollback", "Plan", "Rollback to checkpoint"), + SlashCommandSpec("plan:explain", "Plan", "Explain a decision"), + SlashCommandSpec("plan:errors", "Plan", "Show plan errors"), + SlashCommandSpec("plan:artifacts", "Plan", "Show plan artifacts"), + SlashCommandSpec("plan:inspect", "Plan", "Inspect plan details"), + SlashCommandSpec("project:list", "Project", "List projects"), + SlashCommandSpec("project:create", "Project", "Create project"), + SlashCommandSpec("project:show", "Project", "Show project details"), + SlashCommandSpec("project:delete", "Project", "Delete project"), + SlashCommandSpec("project:inspect", "Project", "Inspect project details"), + SlashCommandSpec("project:context:show", "Project", "Show project context policy"), + SlashCommandSpec("actor:list", "Actor", "List actors"), + SlashCommandSpec("actor:show", "Actor", "Show actor details"), + SlashCommandSpec("actor:set-default", "Actor", "Set default actor"), + SlashCommandSpec("resource:list", "Resource", "List resources"), + SlashCommandSpec("resource:show", "Resource", "Show resource details"), + SlashCommandSpec("resource:tree", "Resource", "Show resource tree"), + SlashCommandSpec("resource:inspect", "Resource", "Inspect resource details"), + SlashCommandSpec("config:list", "Config", "List config entries"), + SlashCommandSpec("config:get", "Config", "Get config value"), + SlashCommandSpec("config:set", "Config", "Set config value"), + SlashCommandSpec("tool:list", "Tool", "List tools"), + SlashCommandSpec("tool:show", "Tool", "Show tool details"), + SlashCommandSpec("skill:list", "Skill", "List skills"), + SlashCommandSpec("skill:show", "Skill", "Show skill details"), + SlashCommandSpec("invariant:list", "Invariant", "List invariants"), + SlashCommandSpec("invariant:add", "Invariant", "Add invariant"), + SlashCommandSpec("invariant:remove", "Invariant", "Remove invariant"), + SlashCommandSpec("profile:list", "Profile", "List automation profiles"), + SlashCommandSpec("profile:show", "Profile", "Show automation profile"), + SlashCommandSpec("context:inspect", "Context", "Inspect context state"), + SlashCommandSpec("context:set", "Context", "Set context policy"), + SlashCommandSpec("context:simulate", "Context", "Simulate context assembly"), + SlashCommandSpec("clear", "Utility", "Clear conversation display"), + SlashCommandSpec("theme", "Utility", "Switch color theme"), + SlashCommandSpec("settings", "Utility", "Open settings"), + SlashCommandSpec("help", "Utility", "Show help"), + SlashCommandSpec("about", "Utility", "Show version information"), + SlashCommandSpec("debug", "Utility", "Toggle debug mode"), +) + + +def slash_command_names() -> list[str]: + """Return command names for overlay filtering and completion.""" + return [spec.command for spec in SLASH_COMMAND_SPECS] + + +def slash_command_groups() -> set[str]: + """Return unique slash command groups represented in the catalog.""" + return {spec.group for spec in SLASH_COMMAND_SPECS}