diff --git a/docs/AUDIT-2026-06.md b/docs/AUDIT-2026-06.md index 57363615..c38ac0eb 100644 --- a/docs/AUDIT-2026-06.md +++ b/docs/AUDIT-2026-06.md @@ -192,6 +192,14 @@ inherited wholesale from Claude Code. `/undo`/`/revert`/`/rewind` into a single rewind UI; evaluate `ide` integration reality. Target end state: **~40 commands**. +**Phase 3 ([issue #73](https://github.com/OpenCoven/coven-code/issues/73)) — landed:** remaining +standalone commands folded under parent commands (`/usage stats`, `/agent`, `/session +fork|branch|tag|add-dir`, `/export copy|share`, `/login switch`, `/providers refresh`, +`/thinking back`, `/config keybindings|theme|output-style|import|advisor`, `/plugin reload`, +`/review comments`, `/status doctor`, `/coven goal`); `/upgrade` dropped as a visible alias of +`/update`. Final visible surface: **42 commands**. Folded names remain hidden one-release +compatibility aliases. + ### Flagged, kept pending verification - `ide` (named) — IDE integration may be real via ACP; verify before removing. diff --git a/docs/commands.md b/docs/commands.md index baede6c9..a77bffb7 100644 --- a/docs/commands.md +++ b/docs/commands.md @@ -8,19 +8,19 @@ This document is the reference for the visible slash commands available in Coven 1. [Command System Overview](#command-system-overview) 2. [Session & Navigation](#session--navigation) -3. [Model & Provider](#model--provider) — `/model`, `/providers`, `/connect`, `/thinking`, `/effort`, `/advisor`, `/fast` -4. [Configuration & Settings](#configuration--settings) — `/config`, `/keybindings`, `/permissions`, `/hooks`, `/mcp`, `/output-style`, `/theme` +3. [Model & Provider](#model--provider) — `/model`, `/providers`, `/connect`, `/thinking`, `/effort`, `/config advisor`, `/fast` +4. [Configuration & Settings](#configuration--settings) — `/config`, `/config keybindings`, `/config theme`, `/config output-style`, `/permissions`, `/hooks`, `/mcp` 5. [Code & Git](#code--git) — `/commit`, `/diff`, `/review`, `/init`, `/search` 6. [Search & Files](#search--files) -7. [Memory & Context](#memory--context) — `/memory`, `/usage`, `/stats`, `/status` -8. [Agents & Tasks](#agents--tasks) — `/agents`, `/tasks`, `/goal`, `/managed-agents`, `/agent` +7. [Memory & Context](#memory--context) — `/memory`, `/usage`, `/usage stats`, `/status` +8. [Agents & Tasks](#agents--tasks) — `/agent`, `/tasks`, `/coven goal` 9. [Planning & Review](#planning--review) — `/plan`, `ultraplan` (CLI) 10. [MCP & Integrations](#mcp--integrations) — `/mcp`, `/skills`, `/plugin`, `/chrome` -11. [Authentication](#authentication) — `/login`, `/logout`, `/switch`, `/refresh` -12. [Display & Terminal](#display--terminal) — `/theme`, `/output-style`, `/incant` -13. [Diagnostics & Info](#diagnostics--info) — `/doctor`, `/version`, `/update` -14. [Export & Sharing](#export--sharing) — `/export`, `/copy`, `/share` -15. [Advanced & Internal](#advanced--internal) — `/thinking`, `/connect`, `/fork`, `/effort`, `/whisper`, `/sandbox`, `/think-back` +11. [Authentication](#authentication) — `/login`, `/logout`, `/login switch`, `/providers refresh` +12. [Display & Terminal](#display--terminal) — `/config theme`, `/config output-style`, `/incant` +13. [Diagnostics & Info](#diagnostics--info) — `/status doctor`, `/version`, `/update` +14. [Export & Sharing](#export--sharing) — `/export`, `/export copy`, `/export share` +15. [Advanced & Internal](#advanced--internal) — `/thinking`, `/connect`, `/session fork`, `/effort`, `/whisper`, `/sandbox`, `/thinking back` 16. [Coven Substrate](#coven-substrate) — `/coven`, `/handoff`, `/familiar` 17. [Additional Commands](#additional-commands) — feedback, config import, plugin reload, named CLI commands 18. [Command Availability](#command-availability) @@ -37,6 +37,8 @@ built-in commands -> user command templates -> discovered skills -> plugin comma Commands support aliases — for example `/h`, `/?`, and `/help` all invoke the same handler. +After the Phase 3 consolidation ([issue #73](https://github.com/OpenCoven/coven-code/issues/73)), the visible command surface is **42 commands**. Every command folded in Phase 3 remains callable under its old standalone name as a hidden compatibility alias for one release. + ### Usage Syntax ``` @@ -103,22 +105,26 @@ Resume a previous session from the session store. Displays a list of recent sess Show or manage conversation sessions. Without arguments, shows the current session status (including the remote session URL when a bridge is active). ``` -/session — show current session status -/session list — list recent sessions -/session rename — rename the current session +/session — show current session status +/session list — list recent sessions +/session rename — rename the current session +/session fork [message_index] — fork into a new session +/session branch [create|switch|list] [name] — branch the conversation +/session tag [list|add|remove] [tag] — toggle a searchable session tag +/session add-dir — add a workspace root ``` -`/session rename` absorbs the former standalone `/rename` command. The new name is used in session listings and exports. +`/session rename` absorbs the former standalone `/rename` command. The new name is used in session listings and exports. `/session branch`, `/session tag`, and `/session add-dir` absorb the former standalone `/branch`, `/tag`, and `/add-dir` commands; the old names remain hidden compatibility aliases for one release. --- -### /fork +### /session fork -Fork the current session into a new independent session that begins from the current conversation state. Useful for exploring two different approaches without losing either. +Fork the current session into a new independent session that begins from the current conversation state. Useful for exploring two different approaches without losing either. Formerly the standalone `/fork` command; the old name remains a hidden compatibility alias for one release. ``` -/fork -/fork +/session fork — fork at the current end of the conversation +/session fork — fork after the given message index ``` --- @@ -195,9 +201,11 @@ Configure extended thinking for the current session. Extended thinking allows th /thinking /thinking on /thinking off +/thinking back [n] — show a previous thinking trace +/thinking back play [n] — replay a trace as an animated walkthrough ``` -See also `/effort` for a higher-level interface to thinking depth. +See also `/effort` for a higher-level interface to thinking depth, and [`/thinking back`](#thinking-back) for viewing previous traces. --- @@ -221,16 +229,16 @@ Set the thinking effort level. This is a convenience wrapper over `/thinking` th --- -### /advisor +### /config advisor -Set or unset a secondary advisor model that provides supplementary suggestions alongside the main model. When set, the advisor model's context is available to improve main-model responses. +Set or unset a secondary advisor model that provides supplementary suggestions alongside the main model. When set, the advisor model's context is available to improve main-model responses. Formerly the standalone `/advisor` command; the old name remains a hidden compatibility alias for one release. ``` -/advisor — show current advisor setting -/advisor claude-opus-4-6 — set advisor model by name -/advisor provider/model — set advisor using provider/model format -/advisor off — disable the advisor -/advisor unset — disable the advisor +/config advisor — show current advisor setting +/config advisor claude-opus-4-6 — set advisor model by name +/config advisor provider/model — set advisor using provider/model format +/config advisor off — disable the advisor +/config advisor unset — disable the advisor ``` The advisor model persists to `~/.coven-code/settings.json` under `advisorModel`. Model IDs must start with `claude-` or contain a `/` (provider/model format). @@ -278,12 +286,12 @@ Common keys: --- -### /keybindings +### /config keybindings -Open the interactive keybinding configurator. Displays all bound actions with their current shortcuts. Select an action to rebind it. Changes are written to `~/.coven-code/keybindings.json`. +Open the interactive keybinding configurator. Displays all bound actions with their current shortcuts. Select an action to rebind it. Changes are written to `~/.coven-code/keybindings.json`. Formerly the standalone `/keybindings` command; the old name remains a hidden compatibility alias for one release. ``` -/keybindings +/config keybindings ``` See [keybindings.md](./keybindings.md) for the full keybindings reference. @@ -339,27 +347,27 @@ Add or remove MCP servers by editing `~/.coven-code/settings.json`. --- -### /output-style +### /config output-style -Select how the model's output is rendered in the terminal. Choices include `auto`, `plain`, `markdown`, `streaming`, and others depending on terminal capabilities. +Select how the model's output is rendered in the terminal. Choices include `auto`, `plain`, `markdown`, `streaming`, and others depending on terminal capabilities. Formerly the standalone `/output-style` command; the old name remains a hidden compatibility alias for one release. ``` -/output-style -/output-style plain -/output-style markdown +/config output-style +/config output-style plain +/config output-style markdown ``` --- -### /theme +### /config theme -Open the interactive theme picker. Preview and select a color theme for the Coven Code TUI. +Open the interactive theme picker. Preview and select a color theme for the Coven Code TUI. Formerly the standalone `/theme` command; the old name remains a hidden compatibility alias for one release. ``` -/theme -/theme dark -/theme light -/theme solarized +/config theme +/config theme dark +/config theme light +/config theme solarized ``` --- @@ -453,6 +461,9 @@ Variants (the former `/security-review` and `/ultrareview` commands fold in here performance, maintainability, error handling, test coverage, API design, and architecture; each finding is tagged by category and severity +/review comments [PR#] — read comments on the active GitHub PR (formerly the + standalone /pr-comments command; the old name remains + a hidden compatibility alias for one release) ``` GitHub posting requires `GITHUB_TOKEN` (a personal access token with repo scope); the PR number is auto-detected from `git remote` or supplied via `CLAUDE_PR_NUMBER`. @@ -517,13 +528,14 @@ Display a detailed token usage breakdown for the current session. Shows input to /usage /usage cost /usage context +/usage stats ``` --- ### /usage cost -Show the total token usage and estimated cost for the current session. Provides a quick summary without the full account/quota context of `/usage`. In the TUI, `/stats` opens the interactive stats dialog. +Show the total token usage and estimated cost for the current session. Provides a quick summary without the full account/quota context of `/usage`. In the TUI, `/usage stats` opens the interactive stats dialog. ``` /usage cost @@ -533,6 +545,18 @@ For aggregate token / cost / tool statistics across saved sessions, use the `sta --- +### /usage stats + +Show a detailed token usage and cost breakdown for the current session, including cache creation/read token counts, turn counts, and session duration. In the TUI this opens the interactive stats dialog. Formerly the standalone `/stats` command; the old name remains a hidden compatibility alias for one release. + +``` +/usage stats +``` + +Use `/usage` for quota and account info, `/usage cost` for a quick cost summary. + +--- + ### /status Show the current session status. Includes active model, permission mode, thinking config, connected MCP servers, and loaded plugins. @@ -545,13 +569,26 @@ Show the current session status. Includes active model, permission mode, thinkin ## Agents & Tasks -### /agents +### /agent + +Single entry point for everything agent-related. Without arguments, lists all available named agents (in the TUI, opens the agents/familiars browser). With a name, shows full details for that agent — its system prompt, model binding, and access level. + +``` +/agent — list named agents / open the agents browser +/agent — show full details for a specific named agent +/agent list|create|edit|delete|reset [name] — manage sub-agent definitions +/agent managed [...] — configure the manager-executor system +``` + +To activate an agent, start Coven Code with `--agent `. See [agents.md](./agents.md) for defining custom agents. + +#### /agent list|create|edit|delete|reset -Browse and manage saved workspace agents and Coven familiars. +Browse and manage saved workspace agents and Coven familiars. Formerly the standalone `/agents` command; the old name remains a hidden compatibility alias for one release. ``` -/agents — open the agents/familiars menu -/agents reset — open reset confirmation +/agent list — list sub-agent definitions +/agent reset — open reset confirmation coven-code agents reset — erase saved user agents and familiar roster ``` @@ -560,6 +597,36 @@ from `~/.coven-code/agents/` and the current workspace's `.coven-code/agents/`, and clears `agents`, `familiar`, and `managed_agents` settings. It does not remove built-in agents, plugin packages, sessions, credentials, or history. +#### /agent managed + +Configure the manager-executor agent architecture, where a manager model delegates subtasks to one or more executor agents working in parallel. Includes budget controls and isolation options. Formerly the standalone `/managed-agents` command; the old name remains a hidden compatibility alias for one release. + +``` +/agent managed — show current configuration +/agent managed status — show current configuration +/agent managed presets — list built-in presets +/agent managed preset — apply a named preset +/agent managed setup — show setup instructions +/agent managed enable — enable managed agents +/agent managed disable — disable managed agents +/agent managed reset — remove all managed-agent configuration +/agent managed configure manager-model — set the manager model +/agent managed configure executor-model — set the executor model +/agent managed configure executor-turns — set executor max turns +/agent managed configure concurrent — set max concurrent executors +/agent managed configure isolation on|off — toggle executor isolation +/agent managed configure budget-split shared — shared token pool +/agent managed configure budget-split percentage: — percentage split (manager gets n%) +/agent managed configure budget-split fixed:: — fixed USD caps (manager / executor) +/agent managed budget — set total budget in USD (0 to clear) +``` + +Model format: `provider/model` (e.g., `anthropic/claude-opus-4-6`, `openai/gpt-4o`). Configuration persists to `~/.coven-code/settings.json` under `managed_agents`. + +> **Preview feature.** Behaviour may change across releases. + +See [Managed Agents](./advanced.md#managed-agents) in the advanced guide. + --- ### /tasks @@ -576,19 +643,19 @@ Manage tracked background tasks. Tasks are shell commands or model invocations r --- -### /goal +### /coven goal -Set a durable multi-turn autonomous goal. When a goal is active, Coven Code continues working across turns until the goal is marked complete, paused, or a 200-turn runaway guard fires. Designed for complex, sustained tasks that would otherwise require repeated manual re-prompting. +Set a durable multi-turn autonomous goal. When a goal is active, Coven Code continues working across turns until the goal is marked complete, paused, or a 200-turn runaway guard fires. Designed for complex, sustained tasks that would otherwise require repeated manual re-prompting. Formerly the standalone `/goal` command; the old name remains a hidden compatibility alias for one release. ``` -/goal — set a new goal and begin working autonomously -/goal --tokens 250K — set a goal with a soft token budget cap -/goal — show current goal status -/goal status — show current goal status -/goal pause — pause the active goal -/goal resume — resume a paused goal -/goal clear — delete the current goal -/goal complete — request a completion audit +/coven goal — set a new goal and begin working autonomously +/coven goal --tokens 250K — set a goal with a soft token budget cap +/coven goal — show current goal status +/coven goal status — show current goal status +/coven goal pause — pause the active goal +/coven goal resume — resume a paused goal +/coven goal clear — delete the current goal +/coven goal complete — request a completion audit ``` When the model believes the goal has been achieved, it calls the `GoalComplete` tool with an audit summary and evidence. Goals can be disabled globally by setting `COVEN_CODE_GOALS=0` in your environment. @@ -597,51 +664,6 @@ See [Goal System](./advanced.md#goal-system) in the advanced guide. --- -### /managed-agents - -Configure the manager-executor agent architecture, where a manager model delegates subtasks to one or more executor agents working in parallel. Includes budget controls and isolation options. - -``` -/managed-agents — show current configuration -/managed-agents status — show current configuration -/managed-agents presets — list built-in presets -/managed-agents preset — apply a named preset -/managed-agents setup — show setup instructions -/managed-agents enable — enable managed agents -/managed-agents disable — disable managed agents -/managed-agents reset — remove all managed-agent configuration -/managed-agents configure manager-model — set the manager model -/managed-agents configure executor-model — set the executor model -/managed-agents configure executor-turns — set executor max turns -/managed-agents configure concurrent — set max concurrent executors -/managed-agents configure isolation on|off — toggle executor isolation -/managed-agents configure budget-split shared — shared token pool -/managed-agents configure budget-split percentage: — percentage split (manager gets n%) -/managed-agents configure budget-split fixed:: — fixed USD caps (manager / executor) -/managed-agents budget — set total budget in USD (0 to clear) -``` - -Model format: `provider/model` (e.g., `anthropic/claude-opus-4-6`, `openai/gpt-4o`). Configuration persists to `~/.coven-code/settings.json` under `managed_agents`. - -> **Preview feature.** Behaviour may change across releases. - -See [Managed Agents](./advanced.md#managed-agents) in the advanced guide. - ---- - -### /agent - -List all available named agents, or show details for a specific agent. Named agents are predefined configurations with their own system prompts, model bindings, and access levels. Useful for discovering what agents are available before starting a session. - -``` -/agent — list all visible named agents with access levels -/agent — show full details for a specific named agent -``` - -To activate an agent, start Coven Code with `--agent `. See [agents.md](./agents.md) for defining custom agents. - ---- - ## Planning & Review ### /plan @@ -706,7 +728,7 @@ Manage plugins. Plugins are loadable modules that can register new commands, too /plugin reload ``` -`/plugin reload` refreshes the active session plugin registry, hook registry, plugin commands, agents, skills, and in-memory MCP server definitions. New plugin MCP servers are included in the initial MCP connection at startup; if a reload adds a new MCP server after startup, start a new session before expecting its tools in the model tool list. +`/plugin reload` (formerly the standalone `/reload-plugins` command, which remains a hidden compatibility alias for one release) refreshes the active session plugin registry, hook registry, plugin commands, agents, skills, and in-memory MCP server definitions. New plugin MCP servers are included in the initial MCP connection at startup; if a reload adds a new MCP server after startup, start a new session before expecting its tools in the model tool list. --- @@ -771,14 +793,14 @@ Remove credentials. By default removes only the **active** profile for the provi --- -### /switch +### /login switch -Switch the active account for a provider. Anthropic by default; pass `--codex` for Codex. Run `/switch` with no arguments to list every stored account and see available profile ids — the active profile in each provider is marked with `*`. +Switch the active account for a provider. Anthropic by default; pass `--codex` for Codex. Run `/login switch` with no arguments to list every stored account and see available profile ids — the active profile in each provider is marked with `*`. Formerly the standalone `/switch` command; the old name remains a hidden compatibility alias for one release. ``` -/switch — list stored accounts across providers -/switch work — set active Anthropic profile to "work" -/switch --codex personal — set active Codex profile to "personal" +/login switch — list stored accounts across providers +/login switch work — set active Anthropic profile to "work" +/login switch --codex personal — set active Codex profile to "personal" ``` Sample listing output: @@ -793,25 +815,25 @@ Codex: --- -### /refresh +### /providers refresh -Refresh the provider authentication state. Forces a token refresh without full re-authentication. Useful when a session token has expired mid-session. +Clear saved provider credentials, provider/model selection, and model caches, then rebuild the live runtime state. After refreshing, run `/connect` to authenticate and choose a provider again. Formerly the standalone `/refresh` command; the old name remains a hidden compatibility alias for one release. ``` -/refresh +/providers refresh ``` --- ## Display & Terminal -### /theme +### /config theme Documented above under [Configuration & Settings](#configuration--settings). --- -### /output-style +### /config output-style Documented above under [Configuration & Settings](#configuration--settings). @@ -882,12 +904,12 @@ Set the prompt bar color for the current session. Accepts standard color names o ## Diagnostics & Info -### /doctor +### /status doctor -Run the Coven Code diagnostics suite. Checks configuration integrity, provider connectivity, tool availability, MCP server health, and reports any issues. +Run the Coven Code diagnostics suite. Checks configuration integrity, provider connectivity, tool availability, MCP server health, and reports any issues. Formerly the standalone `/doctor` command; the old name remains a hidden compatibility alias for one release. ``` -/doctor +/status doctor ``` --- @@ -905,13 +927,11 @@ Display the current Coven Code version string and build metadata. --- ### /update -**Aliases:** `upgrade` -Check for available updates. Queries the GitHub releases API and displays the latest version. If a newer version exists, prints the download URL or upgrade instructions. Does not auto-update. +Check for available updates. Queries the GitHub releases API and displays the latest version. If a newer version exists, prints the download URL or upgrade instructions. Does not auto-update. The former `/upgrade` alias remains a hidden compatibility alias for one release. ``` /update -/upgrade ``` --- @@ -931,24 +951,24 @@ Export the current session transcript. Supported formats include Markdown, JSON, --- -### /copy +### /export copy -Copy the most recent assistant response to the system clipboard. Pass a number to copy the Nth most-recent response. On Linux a `wl-clipboard` or `xclip` backend is used; on macOS and Windows the native clipboard API is used. +Copy the most recent assistant response to the system clipboard. Pass a number to copy the Nth most-recent response. On Linux a `wl-clipboard` or `xclip` backend is used; on macOS and Windows the native clipboard API is used. Formerly the standalone `/copy` command; the old name remains a hidden compatibility alias for one release. ``` -/copy — copy the most recent response -/copy 2 — copy the second most recent response -/copy N — copy the Nth most recent response +/export copy — copy the most recent response +/export copy 2 — copy the second most recent response +/export copy N — copy the Nth most recent response ``` --- -### /share +### /export share -Upload the current session as a secret GitHub gist and return a shareable URL. The session is rendered as a single self-contained HTML file and uploaded via the `gh` CLI; a viewer URL of the form `https://opencoven.github.io/coven-code/session/#` is printed. +Upload the current session as a secret GitHub gist and return a shareable URL. The session is rendered as a single self-contained HTML file and uploaded via the `gh` CLI; a viewer URL of the form `https://opencoven.github.io/coven-code/session/#` is printed. Formerly the standalone `/share` command; the old name remains a hidden compatibility alias for one release. ``` -/share +/export share ``` Requires the GitHub CLI (`gh`) installed and logged in (`gh auth login`). The viewer base URL can be overridden with `COVEN_CODE_SHARE_VIEWER_URL`. Secret gists are unlisted but readable by anyone who has the link. @@ -969,7 +989,7 @@ Documented above under [Model & Provider](#model--provider). --- -### /fork +### /session fork Documented above under [Session & Navigation](#session--navigation). @@ -1016,20 +1036,18 @@ Enable or disable sandboxed execution of shell commands. When sandbox mode is on --- -### /think-back -**Aliases:** `thinkback` +### /thinking back -Display the extended-thinking traces from previous model responses in the current session. Only available when extended thinking was used for those responses. Pass a number to view the Nth most-recent trace. +Display the extended-thinking traces from previous model responses in the current session. Only available when extended thinking was used for those responses. Pass a number to view the Nth most-recent trace. Formerly the standalone `/think-back` command (which itself absorbed `/thinkback-play`); the old name remains a hidden compatibility alias for one release. ``` -/think-back — show the most recent thinking trace -/think-back 2 — show the second most recent thinking trace -/think-back play — replay the most recent trace as an animated walkthrough -/think-back play 2 — replay the second most recent trace -/thinkback — alias +/thinking back — show the most recent thinking trace +/thinking back 2 — show the second most recent thinking trace +/thinking back play — replay the most recent trace as an animated walkthrough +/thinking back play 2 — replay the second most recent trace ``` -`/think-back play` absorbs the former `/thinkback-play` command. Thinking traces appear when the model uses extended thinking mode (see `/thinking`). If no traces are found, Coven Code suggests enabling extended thinking. +Thinking traces appear when the model uses extended thinking mode (see `/thinking`). If no traces are found, Coven Code suggests enabling extended thinking. --- @@ -1177,23 +1195,24 @@ section above. They are grouped by purpose. | Command | Description | |---------|-------------| | `/feedback` (alias `bug`) | Submit feedback about Coven Code. `/feedback report` for a bug report. | -| `/import-config` | Import user-level Claude Code configuration (`CLAUDE.md`, `settings.json`) from `~/.claude` via an interactive dialog with preview and confirmation. | -| `/reload-plugins` | Reload the active session plugin registry, hooks, agents, skills, and MCP definitions. | +| `/config import` | Import user-level Claude Code configuration (`CLAUDE.md`, `settings.json`) from `~/.claude` via an interactive dialog with preview and confirmation. Formerly `/import-config` (hidden compatibility alias for one release). | +| `/plugin reload` | Reload the active session plugin registry, hooks, agents, skills, and MCP definitions. Formerly `/reload-plugins` (hidden compatibility alias for one release). | ### Workspace & GitHub | Command | Description | |---------|-------------| -| `/add-dir` | Add a directory to Coven Code's allowed workspace paths. | -| `/branch` | Create a branch of the current conversation at this point. | -| `/tag` | Toggle a searchable tag on the current session. | -| `/pr-comments` | Get comments from a GitHub pull request. | +| `/session add-dir` | Add a directory to Coven Code's allowed workspace paths. Formerly `/add-dir`. | +| `/session branch` | Create a branch of the current conversation at this point. Formerly `/branch`. | +| `/session tag` | Toggle a searchable tag on the current session. Formerly `/tag`. | +| `/review comments` | Get comments from a GitHub pull request. Formerly `/pr-comments`. | ### Named CLI commands These run as `coven-code ` from the shell. Most have slash -adapters (`/agents`, `/add-dir`, `/branch`, `/tag`, `/pr-comments`); -`ultraplan` and `stats` are CLI-only. +adapters (`/agent`, `/session add-dir`, `/session branch`, +`/session tag`, `/review comments`); `ultraplan` and `stats` are +CLI-only. | Command | Description | |---------|-------------| @@ -1204,7 +1223,7 @@ adapters (`/agents`, `/add-dir`, `/branch`, `/tag`, `/pr-comments`); | `tag` | Toggle a searchable session tag. | | `pr-comments` | Get comments from a GitHub PR. | | `ultraplan` | Launch the Ultraplan agentic code planner with extended thinking. | -| `stats` | Aggregate token / cost / tool stats across saved sessions (in the TUI, `/stats` opens the stats dialog). | +| `stats` | Aggregate token / cost / tool stats across saved sessions (in the TUI, `/usage stats` opens the stats dialog). | --- diff --git a/src-rust/crates/commands/src/lib.rs b/src-rust/crates/commands/src/lib.rs index 76773ec6..1c275278 100644 --- a/src-rust/crates/commands/src/lib.rs +++ b/src-rust/crates/commands/src/lib.rs @@ -269,7 +269,6 @@ pub struct IncantCommand; pub struct SandboxToggleCommand; pub struct UltrareviewCommand; pub struct AdvisorCommand; -pub struct UndoCommand; pub struct RevertCommand; pub struct CheckpointsCommand; pub struct SnapshotDiffCommand; @@ -287,6 +286,9 @@ pub struct NamedCommandAdapter { pub slash_aliases: &'static [&'static str], pub slash_description: &'static str, pub slash_help: &'static str, + /// `true` for one-release compatibility aliases folded into a parent + /// command — still callable, but absent from /help and autocomplete. + pub slash_hidden: bool, } #[derive(serde::Serialize)] @@ -824,7 +826,7 @@ impl SlashCommand for ConfigCommand { "Show or modify configuration settings" } fn help(&self) -> &str { - "Usage: /config [show|get|set|unset|color|vim|voice|statusline|terminal-setup] ...\n\n\ + "Usage: /config [show|get|set|unset|] ...\n\n\ Shows or modifies configuration settings.\n\n\ Core settings:\n\ /config\n\ @@ -833,6 +835,12 @@ impl SlashCommand for ConfigCommand { /config set model \n\ /config set permission-mode \n\ /config unset \n\n\ + Subcommands (absorbing the former standalone commands):\n\ + /config theme [] — show, pick (TUI), or set the theme\n\ + /config keybindings — create or open keybindings.json\n\ + /config output-style [...] — show or switch the output style\n\ + /config import — import CLAUDE.md/settings from ~/.claude\n\ + /config advisor [|off] — set the server-side advisor model\n\n\ UI settings:\n\ /config color []\n\ /config vim [on|off]\n\ @@ -874,6 +882,22 @@ impl SlashCommand for ConfigCommand { } return TerminalSetupCommand.execute("", ctx).await; } + // Phase 3 folds — formerly standalone commands. + "theme" => { + return ThemeCommand.execute(subcommand_args, ctx).await; + } + "keybindings" | "keybinding" => { + return KeybindingsCommand.execute(subcommand_args, ctx).await; + } + "output-style" | "outputstyle" => { + return OutputStyleCommand.execute(subcommand_args, ctx).await; + } + "import" | "import-config" | "import_config" => { + return ImportConfigCommand.execute(subcommand_args, ctx).await; + } + "advisor" => { + return AdvisorCommand.execute(subcommand_args, ctx).await; + } _ => {} } @@ -1114,6 +1138,9 @@ impl SlashCommand for ThemeCommand { fn name(&self) -> &str { "theme" } + fn hidden(&self) -> bool { + true // folded into /config theme; one-release compatibility alias + } fn description(&self) -> &str { "Show or change the current theme" } @@ -1155,6 +1182,9 @@ impl SlashCommand for OutputStyleCommand { fn name(&self) -> &str { "output-style" } + fn hidden(&self) -> bool { + true // folded into /config output-style; one-release compatibility alias + } fn description(&self) -> &str { "Show or switch the current output style" } @@ -1217,6 +1247,9 @@ impl SlashCommand for KeybindingsCommand { fn name(&self) -> &str { "keybindings" } + fn hidden(&self) -> bool { + true // folded into /config keybindings; one-release compatibility alias + } fn description(&self) -> &str { "Create or open ~/.coven-code/keybindings.json" } @@ -1348,10 +1381,26 @@ impl SlashCommand for StatusCommand { "status" } fn description(&self) -> &str { - "Show comprehensive system and session status" + "Show system and session status; /status doctor runs diagnostics" + } + fn help(&self) -> &str { + "Usage: /status [doctor]\n\n\ + Shows authentication, MCP, hook, and session status.\n\ + /status doctor runs the full diagnostics check (formerly /doctor)." } - async fn execute(&self, _args: &str, ctx: &mut CommandContext) -> CommandResult { + async fn execute(&self, args: &str, ctx: &mut CommandContext) -> CommandResult { + // /status doctor absorbs the former standalone /doctor command. + match args.trim() { + "" => {} + "doctor" => return DoctorCommand.execute("", ctx).await, + other => { + return CommandResult::Error(format!( + "Unknown status subcommand '{}'. Use: /status [doctor]", + other + )) + } + } // Auth status let auth_status = match claurst_core::oauth::OAuthTokens::load().await { Some(tokens) => { @@ -1531,6 +1580,9 @@ impl SlashCommand for GoalCommand { fn name(&self) -> &str { "goal" } + fn hidden(&self) -> bool { + true // folded into /coven goal; one-release compatibility alias + } fn description(&self) -> &str { "Set or manage a durable long-running goal for autonomous work" } @@ -1984,10 +2036,10 @@ impl SlashCommand for UsageCommand { "Show API usage, quotas, and rate limit status" } fn help(&self) -> &str { - "Usage: /usage [cost|context]\n\n\ + "Usage: /usage [cost|context|stats]\n\n\ Shows current session API usage and account quota information.\n\ - Use /usage cost for the session cost breakdown or /usage context for context-window details.\n\ - The legacy /cost and /context commands remain hidden compatibility aliases." + Use /usage cost for the session cost breakdown, /usage context for\n\ + context-window details, or /usage stats for the full statistics view." } async fn execute(&self, args: &str, ctx: &mut CommandContext) -> CommandResult { @@ -1998,9 +2050,10 @@ impl SlashCommand for UsageCommand { "" | "summary" | "quota" | "status" => {} "cost" | "costs" => return CostCommand.execute(rest, ctx).await, "context" | "window" => return ContextCommand.execute(rest, ctx).await, + "stats" => return StatsCommand.execute(rest, ctx).await, other => { return CommandResult::Error(format!( - "Unknown usage view '{}'. Use: /usage [cost|context]", + "Unknown usage view '{}'. Use: /usage [cost|context|stats]", other )) } @@ -2224,11 +2277,14 @@ impl SlashCommand for ReloadPluginsCommand { fn name(&self) -> &str { "reload-plugins" } + fn hidden(&self) -> bool { + true // folded into /plugin reload; one-release compatibility alias + } fn description(&self) -> &str { "Reload all plugins without restarting" } fn help(&self) -> &str { - "Usage: /reload-plugins\n\ + "Usage: /plugin reload\n\ Reloads all plugins and shows what changed." } @@ -2337,11 +2393,14 @@ impl SlashCommand for DoctorCommand { fn name(&self) -> &str { "doctor" } + fn hidden(&self) -> bool { + true // folded into /status doctor; one-release compatibility alias + } fn description(&self) -> &str { "Check system health and diagnose issues" } fn help(&self) -> &str { - "Usage: /doctor\n\ + "Usage: /status doctor\n\ Runs a comprehensive system diagnostics check:\n\ - API key validation (live GET /v1/models call)\n\ - Git availability\n\ @@ -2768,15 +2827,23 @@ impl SlashCommand for LoginCommand { "Authenticate with Anthropic or Codex (multi-account)" } fn help(&self) -> &str { - "Usage: /login [--console] [--codex] [--label ]\n\n\ + "Usage: /login [--console] [--codex] [--label ] | /login switch [--codex] [profile-id]\n\n\ Start an OAuth login. Anthropic OAuth requires a configured Coven Code\n\ client ID via COVEN_CODE_ANTHROPIC_OAUTH_CLIENT_ID; use\n\ ANTHROPIC_API_KEY until that client is configured. Pass `--codex` to\n\ add a ChatGPT/Codex account. `--label work` names the saved profile so\n\ - you can `switch` to it later by that name." + you can switch to it later by that name.\n\n\ + /login switch makes a stored account active (formerly /switch);\n\ + with no profile id it lists stored accounts." } - async fn execute(&self, args: &str, _ctx: &mut CommandContext) -> CommandResult { + async fn execute(&self, args: &str, ctx: &mut CommandContext) -> CommandResult { + // /login switch absorbs the former standalone /switch command. + if let Some(rest) = args.trim().strip_prefix("switch") { + if rest.is_empty() || rest.starts_with(char::is_whitespace) { + return SwitchCommand.execute(rest.trim(), ctx).await; + } + } let tokens: Vec<&str> = args.split_whitespace().collect(); let use_codex = tokens.contains(&"--codex"); let login_with_claude_ai = !tokens.contains(&"--console"); @@ -2951,14 +3018,17 @@ impl SlashCommand for SwitchCommand { fn name(&self) -> &str { "switch" } + fn hidden(&self) -> bool { + true // folded into /login switch; one-release compatibility alias + } fn description(&self) -> &str { "Switch the active account for a provider" } fn help(&self) -> &str { - "Usage: /switch [--codex] \n\n\ + "Usage: /login switch [--codex] \n\n\ Make a stored account active. Defaults to Anthropic; pass `--codex`\n\ - to switch the Codex account instead. Run /switch with no arguments\n\ - to list stored accounts and see available profile ids." + to switch the Codex account instead. Run /login switch with no\n\ + arguments to list stored accounts and see available profile ids." } async fn execute(&self, args: &str, ctx: &mut CommandContext) -> CommandResult { @@ -2978,7 +3048,7 @@ impl SlashCommand for SwitchCommand { let Some(id) = id else { return CommandResult::Error(format!( - "Usage: /switch {} (try /accounts to see options)", + "Usage: /login switch {} (run /login switch to see options)", if use_codex { "--codex " } else { "" } )); }; @@ -3000,18 +3070,21 @@ impl SlashCommand for RefreshCommand { fn name(&self) -> &str { "refresh" } + fn hidden(&self) -> bool { + true // folded into /providers refresh; one-release compatibility alias + } fn description(&self) -> &str { "Clear saved provider auth and model caches" } fn help(&self) -> &str { - "Usage: /refresh\n\n\ + "Usage: /providers refresh\n\n\ Clears saved provider credentials, provider/model selection, and model caches, then rebuilds the live runtime state.\n\ After refreshing, run /connect to authenticate and choose a provider again." } async fn execute(&self, args: &str, _ctx: &mut CommandContext) -> CommandResult { if !args.trim().is_empty() { - return CommandResult::Error("Usage: /refresh".to_string()); + return CommandResult::Error("Usage: /providers refresh".to_string()); } CommandResult::RefreshProviderState } @@ -3121,13 +3194,14 @@ impl SlashCommand for ReviewCommand { "Review code changes via LLM and optionally post to GitHub PR" } fn help(&self) -> &str { - "Usage: /review [base-ref] | /review security [path] | /review ultra [path]\n\n\ + "Usage: /review [base-ref] | /review security [path] | /review ultra [path] | /review comments [PR#]\n\n\ Runs `git diff ...HEAD` (or `git diff --cached` when no base is given),\n\ sends the diff to the LLM for a structured review, then optionally posts the\n\ review as a comment to the associated GitHub PR.\n\n\ Variants:\n\ /review security — security-focused review (vulnerabilities, secrets, injection)\n\ - /review ultra — exhaustive multi-dimensional review\n\n\ + /review ultra — exhaustive multi-dimensional review\n\ + /review comments — read comments on the active GitHub PR (formerly /pr-comments)\n\n\ GitHub posting requires:\n\ GITHUB_TOKEN — a personal access token with repo scope\n\ CLAUDE_PR_NUMBER — the PR number (auto-detected from `git remote` if absent)\n\n\ @@ -3148,6 +3222,8 @@ impl SlashCommand for ReviewCommand { match head { "security" => return SecurityReviewCommand.execute(rest, ctx).await, "ultra" | "ultrareview" => return UltrareviewCommand.execute(rest, ctx).await, + // /review comments absorbs the former standalone /pr-comments. + "comments" => return execute_named_command_from_slash("pr-comments", rest, ctx), _ => {} } let base = trimmed; @@ -3460,6 +3536,9 @@ impl SlashCommand for ImportConfigCommand { fn name(&self) -> &str { "import-config" } + fn hidden(&self) -> bool { + true // folded into /config import; one-release compatibility alias + } fn description(&self) -> &str { "Import CLAUDE.md and settings.json from ~/.claude" } @@ -4438,14 +4517,34 @@ impl SlashCommand for SessionCommand { vec!["remote"] } fn description(&self) -> &str { - "Show or manage conversation sessions" + "Browse and manage sessions (rename, fork, branch, tag, add-dir)" + } + fn help(&self) -> &str { + "Usage: /session [list|rename|fork|branch|tag|add-dir] [...]\n\n\ + Without arguments, shows the current session and recent sessions.\n\n\ + Subcommands (absorbing the former standalone commands):\n\ + /session list — list saved sessions\n\ + /session rename — rename the current session\n\ + /session fork [message_index] — fork into a new session\n\ + /session branch [create|switch|list] [name]\n\ + /session tag [list|add|remove] [tag]\n\ + /session add-dir <path> — add a workspace root" } async fn execute(&self, args: &str, ctx: &mut CommandContext) -> CommandResult { let trimmed = args.trim(); - // /session rename [...] absorbs the former standalone /rename command. - if let Some(rest) = trimmed.strip_prefix("rename") { - return RenameCommand.execute(rest.trim(), ctx).await; + let (head, rest) = match trimmed.split_once(char::is_whitespace) { + Some((h, r)) => (h, r.trim()), + None => (trimmed, ""), + }; + match head { + // Each arm absorbs a former standalone command. + "rename" => return RenameCommand.execute(rest, ctx).await, + "fork" => return ForkCommand.execute(rest, ctx).await, + "branch" => return execute_named_command_from_slash("branch", rest, ctx), + "tag" => return execute_named_command_from_slash("tag", rest, ctx), + "add-dir" => return execute_named_command_from_slash("add-dir", rest, ctx), + _ => {} } match trimmed { "list" => { @@ -4531,7 +4630,7 @@ impl SlashCommand for SessionCommand { } } _ => CommandResult::Error(format!( - "Unknown subcommand: {}\n\nUsage: /session [list]", + "Unknown subcommand: {}\n\nUsage: /session [list|rename|fork|branch|tag|add-dir]", args )), } @@ -4545,11 +4644,14 @@ impl SlashCommand for ForkCommand { fn name(&self) -> &str { "fork" } + fn hidden(&self) -> bool { + true // folded into /session fork; one-release compatibility alias + } fn description(&self) -> &str { "Fork the current session into a new branch" } fn help(&self) -> &str { - "Usage: /fork [message_index]\n\n\ + "Usage: /session fork [message_index]\n\n\ Fork the current session at the specified message index (or at the\n\ current point if no index is given). Creates a new session containing\n\ messages up to the fork point.\n\n\ @@ -4595,13 +4697,27 @@ impl SlashCommand for ThinkingCommand { "thinking" } fn description(&self) -> &str { - "Toggle extended thinking mode" + "Configure extended thinking; /thinking back shows previous traces" + } + fn help(&self) -> &str { + "Usage: /thinking | /thinking back [n] | /thinking back play [n]\n\n\ + Shows extended-thinking availability for the active model.\n\ + /thinking back displays thinking traces from previous responses\n\ + (formerly /think-back); `play` replays a trace as an animated\n\ + walkthrough." } fn aliases(&self) -> Vec<&str> { vec!["think"] } - async fn execute(&self, _args: &str, ctx: &mut CommandContext) -> CommandResult { + async fn execute(&self, args: &str, ctx: &mut CommandContext) -> CommandResult { + // /thinking back absorbs the former standalone /think-back command + // (which itself absorbed /thinkback-play as `back play`). + if let Some(rest) = args.trim().strip_prefix("back") { + if rest.is_empty() || rest.starts_with(char::is_whitespace) { + return ThinkBackCommand.execute(rest.trim(), ctx).await; + } + } // Extended thinking is configured through the model; just inform the user let model = ctx.config.effective_model(); if model.contains("claude-3-5") || model.contains("claude-3.5") { @@ -4784,25 +4900,39 @@ impl SlashCommand for ExportCommand { "export" } fn description(&self) -> &str { - "Export conversation to markdown or JSON" + "Export conversation (file, clipboard, or shareable link)" } fn help(&self) -> &str { - "Usage: /export [--format markdown|json] [--output <file>]\n\n\ + "Usage: /export [--format markdown|json] [--output <file>] | /export copy [n] | /export share\n\n\ Export the current conversation.\n\n\ Flags:\n\ --format markdown Render as readable Markdown (default for .md files)\n\ --format json Full structured JSON export (default)\n\ --output <path> Write to file; if omitted, prints to the terminal\n\n\ + Variants (absorbing the former standalone commands):\n\ + /export copy [n] Copy the Nth most-recent assistant response to the clipboard\n\ + /export share Upload the session as a secret gist and print a shareable URL\n\n\ Examples:\n\ /export\n\ /export --format markdown\n\ - /export --format json --output chat.json\n\ - /export --output conversation.md" + /export copy\n\ + /export share" } async fn execute(&self, args: &str, ctx: &mut CommandContext) -> CommandResult { // ── Parse flags ──────────────────────────────────────────────────── let args = args.trim(); + // /export copy and /export share absorb the former standalone + // /copy and /share commands. + let (head, rest) = match args.split_once(char::is_whitespace) { + Some((h, r)) => (h, r.trim()), + None => (args, ""), + }; + match head { + "copy" => return CopyCommand.execute(rest, ctx).await, + "share" => return ShareCommand.execute(rest, ctx).await, + _ => {} + } let mut format: Option<&str> = None; // "markdown" | "json" let mut output_path: Option<String> = None; @@ -4929,11 +5059,14 @@ impl SlashCommand for ShareCommand { fn name(&self) -> &str { "share" } + fn hidden(&self) -> bool { + true // folded into /export share; one-release compatibility alias + } fn description(&self) -> &str { "Upload the current session as a secret GitHub gist and return a shareable URL" } fn help(&self) -> &str { - "Usage: /share\n\n\ + "Usage: /export share\n\n\ Renders the current session as a single self-contained HTML file,\n\ uploads it as a secret GitHub gist via the `gh` CLI, and prints a\n\ viewer URL of the form https://opencoven.github.io/coven-code/session/#<gist-id>.\n\n\ @@ -5221,14 +5354,17 @@ impl SlashCommand for StatsCommand { fn name(&self) -> &str { "stats" } + fn hidden(&self) -> bool { + true // folded into /usage stats; one-release compatibility alias + } fn description(&self) -> &str { "Show token usage and cost statistics" } fn help(&self) -> &str { - "Usage: /stats\n\n\ + "Usage: /usage stats\n\n\ Shows detailed token usage and cost breakdown for the current session,\n\ including cache creation/read token counts, turn counts, and session duration.\n\ - Use /usage for quota and account info. Use /cost for a quick cost summary." + Use /usage for quota and account info, /usage cost for a quick cost summary." } async fn execute(&self, _args: &str, ctx: &mut CommandContext) -> CommandResult { @@ -5638,11 +5774,14 @@ impl SlashCommand for CopyCommand { fn name(&self) -> &str { "copy" } + fn hidden(&self) -> bool { + true // folded into /export copy; one-release compatibility alias + } fn description(&self) -> &str { "Copy the last assistant response to the clipboard" } fn help(&self) -> &str { - "Usage: /copy [n]\n\n\ + "Usage: /export copy [n]\n\n\ Copies the most recent assistant response to the system clipboard.\n\ Optionally pass a number to copy the Nth most-recent response." } @@ -6747,6 +6886,9 @@ impl SlashCommand for AdvisorCommand { fn name(&self) -> &str { "advisor" } + fn hidden(&self) -> bool { + true // folded into /config advisor; one-release compatibility alias + } fn description(&self) -> &str { "Set or unset the server-side advisor model" } @@ -6888,6 +7030,9 @@ impl SlashCommand for ThinkBackCommand { fn name(&self) -> &str { "think-back" } + fn hidden(&self) -> bool { + true // folded into /thinking back; one-release compatibility alias + } fn aliases(&self) -> Vec<&str> { vec!["thinkback"] } @@ -7435,6 +7580,10 @@ impl SlashCommand for NamedCommandAdapter { self.slash_name } + fn hidden(&self) -> bool { + self.slash_hidden + } + fn aliases(&self) -> Vec<&str> { self.slash_aliases.to_vec() } @@ -7452,32 +7601,6 @@ impl SlashCommand for NamedCommandAdapter { } } -// ---- /undo (alias for /revert targeting the most recent assistant turn) ---- - -#[async_trait] -impl SlashCommand for UndoCommand { - fn name(&self) -> &str { - "undo" - } - fn hidden(&self) -> bool { - true - } - fn aliases(&self) -> Vec<&str> { - vec![] - } - fn description(&self) -> &str { - "Revert all file changes from the last assistant turn (alias: /revert)" - } - fn help(&self) -> &str { - "Usage: /undo\n\nReverts all file changes made during the most recent assistant turn.\n\ - For finer control use /revert. To list what changed, use /checkpoints." - } - - async fn execute(&self, _args: &str, ctx: &mut CommandContext) -> CommandResult { - RevertCommand.execute("", ctx).await - } -} - // ---- /revert --------------------------------------------------------------- #[async_trait] @@ -7779,13 +7902,28 @@ impl SlashCommand for ProvidersCommand { "providers" } fn description(&self) -> &str { - "List available AI providers and their status" + "List AI providers; /providers refresh clears auth and model caches" } fn help(&self) -> &str { - "Usage: /providers\n\nList all providers registered in the model registry with their\nmodel counts, context windows, and pricing information." + "Usage: /providers [refresh]\n\n\ + List all providers registered in the model registry with their\n\ + model counts, context windows, and pricing information.\n\n\ + /providers refresh clears saved provider credentials and model\n\ + caches, then rebuilds the live runtime state (formerly /refresh)." } - async fn execute(&self, _args: &str, _ctx: &mut CommandContext) -> CommandResult { + async fn execute(&self, args: &str, ctx: &mut CommandContext) -> CommandResult { + // /providers refresh absorbs the former standalone /refresh command. + match args.trim() { + "" => {} + "refresh" => return RefreshCommand.execute("", ctx).await, + other => { + return CommandResult::Error(format!( + "Unknown providers subcommand '{}'. Use: /providers [refresh]", + other + )) + } + } let registry = claurst_api::ModelRegistry::new(); let all = registry.list_all(); @@ -7865,15 +8003,35 @@ impl SlashCommand for AgentCommand { "agent" } fn description(&self) -> &str { - "List available agents or get info about a specific agent" + "Browse, inspect, and manage familiars and sub-agents" } fn help(&self) -> &str { - "Usage: /agent [name]\n\nWithout arguments, lists all available named agents.\nWith a name, shows details for that agent.\n\nTo use an agent, start Coven Code with: --agent <name>" + "Usage: /agent [name] | /agent [list|create|edit|delete|reset] [name] | /agent managed [...]\n\n\ + Without arguments, lists all available named agents (in the TUI, opens the agents browser).\n\ + With a name, shows details for that agent.\n\ + /agent list|create|edit|delete|reset manage sub-agent definitions (formerly /agents).\n\ + /agent managed configures the manager-executor system (formerly /managed-agents).\n\n\ + To use an agent, start Coven Code with: --agent <name>" } async fn execute(&self, args: &str, ctx: &mut CommandContext) -> CommandResult { use std::collections::HashMap; + let trimmed = args.trim(); + let (head, rest) = match trimmed.split_once(char::is_whitespace) { + Some((h, r)) => (h, r.trim()), + None => (trimmed, ""), + }; + match head { + // /agent managed … absorbs the former standalone /managed-agents. + "managed" => return ManagedAgentsCommand.execute(rest, ctx).await, + // /agent list|create|… absorbs the former standalone /agents. + "list" | "create" | "edit" | "delete" | "reset" => { + return execute_named_command_from_slash("agents", trimmed, ctx); + } + _ => {} + } + // Merge built-in defaults with user-defined agents (user wins on collision). let mut all_agents: HashMap<String, claurst_core::AgentDefinition> = claurst_core::default_agents(); @@ -8116,6 +8274,9 @@ impl SlashCommand for ManagedAgentsCommand { fn name(&self) -> &str { "managed-agents" } + fn hidden(&self) -> bool { + true // folded into /agent managed; one-release compatibility alias + } fn description(&self) -> &str { "Configure and manage the manager-executor agent architecture" } @@ -8513,6 +8674,10 @@ fn coven_help_text() -> &'static str { Coven Calls (delegation ledger)\n\ /coven calls [--limit N] Read ~/.coven/cave-coven-calls.json\n\ \n\ + Durable goals\n\ + /coven goal [<objective>|status|pause|resume|clear|complete]\n\ + /coven goal --tokens 250K <objective>\n\ + \n\ Parallel-work protocol\n\ /coven claim acquire|release|status|heartbeat|canary [args]\n\ /coven hooks-install Install git hooks for the claim protocol\n\ @@ -8760,7 +8925,7 @@ impl SlashCommand for CovenCommand { fn help(&self) -> &str { coven_help_text() } - async fn execute(&self, args: &str, _ctx: &mut CommandContext) -> CommandResult { + async fn execute(&self, args: &str, ctx: &mut CommandContext) -> CommandResult { use claurst_core::coven_shared::DaemonClient; let trimmed = args.trim(); @@ -8787,6 +8952,9 @@ impl SlashCommand for CovenCommand { } match sub { + // /coven goal absorbs the former standalone /goal command: + // durable goals are Coven-substrate workflow state. + "goal" => return GoalCommand.execute(rest, ctx).await, // Read-only listings — use the in-process client. "sessions" => { let include_archived = rest.split_whitespace().any(|t| t == "--all" || t == "-a"); @@ -9211,11 +9379,9 @@ static COMMANDS: Lazy<Vec<Box<dyn SlashCommand>>> = Lazy::new(|| { Box::new(HelpCommand), Box::new(ClearCommand), Box::new(CompactCommand), - Box::new(CostCommand), Box::new(ExitCommand), Box::new(ModelCommand), Box::new(ConfigCommand), - Box::new(ColorCommand), Box::new(PluginCommand), Box::new(VersionCommand), Box::new(ResumeCommand), @@ -9254,6 +9420,7 @@ static COMMANDS: Lazy<Vec<Box<dyn SlashCommand>>> = Lazy::new(|| { Box::new(CommitCommand), Box::new(NamedCommandAdapter { slash_name: "add-dir", + slash_hidden: true, target_name: "add-dir", slash_aliases: &[], slash_description: "Add a directory to Coven Code's allowed workspace paths", @@ -9261,6 +9428,7 @@ static COMMANDS: Lazy<Vec<Box<dyn SlashCommand>>> = Lazy::new(|| { }), Box::new(NamedCommandAdapter { slash_name: "agents", + slash_hidden: true, target_name: "agents", slash_aliases: &[], slash_description: "Manage and configure sub-agents", @@ -9268,6 +9436,7 @@ static COMMANDS: Lazy<Vec<Box<dyn SlashCommand>>> = Lazy::new(|| { }), Box::new(NamedCommandAdapter { slash_name: "branch", + slash_hidden: true, target_name: "branch", slash_aliases: &[], slash_description: "Create a branch of the current conversation at this point", @@ -9275,6 +9444,7 @@ static COMMANDS: Lazy<Vec<Box<dyn SlashCommand>>> = Lazy::new(|| { }), Box::new(NamedCommandAdapter { slash_name: "tag", + slash_hidden: true, target_name: "tag", slash_aliases: &[], slash_description: "Toggle a searchable tag on the current session", @@ -9282,20 +9452,16 @@ static COMMANDS: Lazy<Vec<Box<dyn SlashCommand>>> = Lazy::new(|| { }), Box::new(NamedCommandAdapter { slash_name: "pr-comments", + slash_hidden: true, target_name: "pr-comments", slash_aliases: &[], slash_description: "Get comments from a GitHub pull request", - slash_help: "Usage: /pr-comments <PR-number>", + slash_help: "Usage: /review comments [PR-number]", }), // Batch-1 new commands - Box::new(ContextCommand), Box::new(CopyCommand), Box::new(ChromeCommand), - Box::new(VimCommand), - Box::new(VoiceCommand), Box::new(UpgradeCommand), - Box::new(StatuslineCommand), - Box::new(TerminalSetupCommand), Box::new(FastCommand), Box::new(ThinkBackCommand), // /whisper (BtwCommand) and /sandbox (SandboxToggleCommand) @@ -9303,9 +9469,6 @@ static COMMANDS: Lazy<Vec<Box<dyn SlashCommand>>> = Lazy::new(|| { Box::new(SandboxToggleCommand), // Advisor Box::new(AdvisorCommand), - // Snapshot / revert system - Box::new(UndoCommand), - Box::new(RevertCommand), // Multi-provider support Box::new(ProvidersCommand), Box::new(ConnectCommand), @@ -9662,8 +9825,11 @@ mod tests { } #[test] - fn phase_two_legacy_commands_are_hidden_but_callable() { - let hidden_legacy = [ + fn phase_two_legacy_commands_are_fully_removed() { + // The Phase 2 hidden aliases' one-release grace period has ended: + // the names no longer resolve at all. Their impls survive only as + // delegation targets of /config, /usage, and /rewind. + let removed_legacy = [ "color", "context", "cost", @@ -9675,23 +9841,10 @@ mod tests { "voice", ]; - for name in hidden_legacy { - let command = find_command(name).unwrap_or_else(|| panic!("{name} should resolve")); + for name in removed_legacy { assert!( - command.hidden(), - "{name} should stay callable as a hidden one-release compatibility alias" - ); - } - - let visible_names: std::collections::HashSet<&str> = all_commands() - .iter() - .filter(|command| !command.hidden()) - .map(|command| command.name()) - .collect(); - for name in hidden_legacy { - assert!( - !visible_names.contains(name), - "{name} should not be a visible primary command" + find_command(name).is_none(), + "{name} should no longer resolve after the alias grace period" ); } } @@ -9807,7 +9960,6 @@ mod tests { "help", "clear", "compact", - "cost", "exit", "model", "config", @@ -9934,9 +10086,11 @@ mod tests { #[tokio::test] async fn test_cost_command_returns_message() { + // /cost is no longer registered (expired Phase 2 alias); the impl + // remains as the delegation target of /usage cost. let mut ctx = make_ctx(); - let cmd = find_command("cost").unwrap(); - let result = cmd.execute("", &mut ctx).await; + assert!(find_command("cost").is_none()); + let result = UsageCommand.execute("cost", &mut ctx).await; assert!(matches!(result, CommandResult::Message(_))); } @@ -10245,10 +10399,7 @@ mod tests { // `App::intercept_slash_command_with_args` (sends the current // session context to a Coven familiar). It is documented in // docs/familiars.md and lives in tui/src/handoff.rs. - // - stats: intercepted directly by the TUI to open the live stats - // dialog; the named CLI `stats` command handles aggregate saved - // session reports outside the TUI. - const ALLOWED_ALIAS_NAMES: &[&str] = &["quit", "settings", "survey", "handoff", "stats"]; + const ALLOWED_ALIAS_NAMES: &[&str] = &["quit", "settings", "survey", "handoff"]; let prompt_names: HashSet<&str> = claurst_tui::app::PROMPT_SLASH_COMMANDS .iter() diff --git a/src-rust/crates/tui/src/app.rs b/src-rust/crates/tui/src/app.rs index 33904749..658bc340 100644 --- a/src-rust/crates/tui/src/app.rs +++ b/src-rust/crates/tui/src/app.rs @@ -53,13 +53,9 @@ use tracing::debug; /// enforces that. pub const PROMPT_SLASH_COMMANDS: &[(&str, &str)] = &[ ( - "add-dir", - "Add an extra workspace root to the active session", + "agent", + "Browse, inspect, and manage familiars and sub-agents", ), - ("advisor", "Set or unset the server-side advisor model"), - ("agent", "List available familiars or show familiar details"), - ("agents", "Browse familiar definitions and active familiars"), - ("branch", "Create or switch session branches"), ("chrome", "Browser automation via Chrome DevTools Protocol"), ("clear", "Clear the conversation transcript"), ( @@ -67,102 +63,84 @@ pub const PROMPT_SLASH_COMMANDS: &[(&str, &str)] = &[ "Stage and commit changes (model drafts the message)", ), ("compact", "Compact the conversation context"), - ("config", "Open settings"), + ( + "config", + "Open settings (theme, keybindings, output-style, import, advisor)", + ), ("connect", "Connect an AI provider"), - ("copy", "Copy the last assistant response to clipboard"), ( "coven", - "Drive the local Coven daemon (sessions, harness runs, rituals)", + "Drive the local Coven daemon (sessions, runs, rituals, goals)", ), ("diff", "Inspect the current git diff"), - ("doctor", "Run diagnostics"), ("effort", "Set effort level (low/medium/high/max)"), ("exit", "Quit Coven Code"), - ("export", "Export conversation"), + ( + "export", + "Export conversation (file, clipboard, or shareable link)", + ), ( "familiar", "Set your active familiar — changes the TUI mascot live", ), ("fast", "Toggle fast mode"), ("feedback", "Open session feedback survey"), - ("fork", "Fork session into a new branch"), - ("goal", "Set or view the current session goal"), ( "handoff", "Hand off current session context to a Coven familiar", ), ("help", "Show help"), ("hooks", "Browse configured hooks (read-only)"), - ( - "import-config", - "Import CLAUDE.md and settings.json from ~/.claude", - ), ( "incant", "Cast a speech incantation (caveman, rocky) or lift it with off", ), ("init", "Initialize AGENTS.md for this project"), - ("keybindings", "Show keybinding configuration"), ("login", "Log in to Coven Code"), ("logout", "Log out of Coven Code"), - ( - "managed-agents", - "Configure manager-executor managed agent system", - ), ("mcp", "Browse configured MCP servers"), ("memory", "Browse and open AGENTS.md memory files"), ("model", "Change the AI model"), - ("output-style", "Toggle output style (auto/stream/verbose)"), ("permissions", "Manage tool permission rules"), ("plan", "Enter plan mode (read-only)"), ("plugin", "Manage plugins (list/info/enable/disable/reload)"), ( - "pr-comments", - "Read or post comments on the active GitHub PR", + "providers", + "List AI providers; refresh clears auth and model caches", ), - ("providers", "List available AI providers and their status"), ("quit", "Exit Coven Code"), - ("refresh", "Clear saved provider auth and model caches"), + ("resume", "Resume a previous session"), ( - "reload-plugins", - "Reload the active session plugin registry", + "review", + "Review changes (git diff), security/ultra variants, PR comments", ), - ("resume", "Resume a previous session"), - ("review", "Review changes (git diff)"), ( "rewind", "Rewind the conversation or roll back file changes", ), ("sandbox", "Toggle sandboxed shell execution"), ("search", "Search the codebase by natural language or regex"), - ("session", "Browse and manage sessions"), - ("settings", "Open settings"), ( - "share", - "Upload the current session as a secret gist and get a shareable URL", + "session", + "Browse and manage sessions (rename, fork, branch, tag, add-dir)", ), + ("settings", "Open settings"), ("skills", "List and manage skills"), - ("status", "Show the current session status"), - ("stats", "Open the interactive session statistics dialog"), + ( + "status", + "Show session status; /status doctor runs diagnostics", + ), ("survey", "Open session feedback survey"), - ("switch", "Switch the active account for a provider"), - ("tag", "Tag the current session with a label"), ("tasks", "Manage tracked background tasks"), - ("theme", "Open the theme picker"), ( - "think-back", - "Show extended-thinking traces from previous responses", + "thinking", + "Configure extended thinking; back shows previous traces", ), - ("thinking", "Configure extended thinking for the session"), ( "update", "Check for updates and upgrade to the latest version", ), - ( - "upgrade", - "Check for updates and upgrade to the latest version", - ), - ("usage", "Detailed per-call token usage breakdown"), + ("usage", "Token usage, quotas, and session statistics"), ("version", "Display the current Coven Code version"), ( "whisper", @@ -172,16 +150,12 @@ pub const PROMPT_SLASH_COMMANDS: &[(&str, &str)] = &[ fn help_command_category(name: &str) -> &'static str { match name { - "connect" | "model" | "providers" | "refresh" | "fast" | "effort" => "Model & Provider", - "diff" | "review" | "rewind" | "export" | "copy" | "share" => "Review & History", - "usage" | "doctor" | "status" | "stats" => "Diagnostics", - "config" | "settings" | "theme" | "keybindings" | "hooks" | "mcp" | "import-config" => { - "Workspace" - } - "agent" | "agents" | "memory" | "plugin" | "feedback" | "survey" => "Tools", - "session" | "resume" | "fork" | "clear" | "compact" | "whisper" | "quit" | "exit" => { - "Session" - } + "connect" | "model" | "providers" | "fast" | "effort" => "Model & Provider", + "diff" | "review" | "rewind" | "export" => "Review & History", + "usage" | "status" => "Diagnostics", + "config" | "settings" | "hooks" | "mcp" => "Workspace", + "agent" | "memory" | "plugin" | "feedback" | "survey" => "Tools", + "session" | "resume" | "clear" | "compact" | "whisper" | "quit" | "exit" => "Session", "coven" | "handoff" | "familiar" => "Coven Substrate", _ => "Commands", } @@ -2450,7 +2424,55 @@ impl App { /// Handle slash commands that should open UI screens rather than execute /// as normal commands. Returns `true` if the command was intercepted. pub fn intercept_slash_command_with_args(&mut self, cmd: &str, args: &str) -> bool { - if !args.trim().is_empty() && matches!(cmd, "config" | "settings" | "usage") { + // /usage stats opens the same live dialog the former standalone + // /stats did; other /usage views render via the command layer. + if cmd == "usage" && args.trim() == "stats" { + return self.intercept_slash_command("stats"); + } + // /agent is the umbrella for the former /agents browser: bare /agent + // opens the TUI browser, /agent reset jumps to the reset confirm, + // and anything else (list/create/<name>/managed …) goes to the + // command layer. + if cmd == "agent" { + let sub = args.trim(); + if sub.is_empty() { + return self.intercept_slash_command("agents"); + } + if sub == "reset" { + self.open_agents_menu(); + self.agents_menu.route = AgentsRoute::ResetConfirm; + return true; + } + return false; + } + // /config subcommands that map to live TUI surfaces re-route to the + // intercepts the former standalone commands used; everything else + // (set/get/unset, color, vim on, theme dark, advisor …) renders via + // the command layer. + if matches!(cmd, "config" | "settings") && !args.trim().is_empty() { + return match args.trim() { + "theme" => self.intercept_slash_command("theme"), + "keybindings" => self.intercept_slash_command("keybindings"), + "output-style" => self.intercept_slash_command("output-style"), + "import" => self.intercept_slash_command("import-config"), + _ => false, + }; + } + if !args.trim().is_empty() && matches!(cmd, "usage" | "session") { + return false; + } + // /review comments reads PR comments via the command layer; other + // /review forms keep opening the diff viewer. + if cmd == "review" && args.split_whitespace().next() == Some("comments") { + return false; + } + // /export copy reuses the live clipboard intercept; every other + // /export variant (share, copy <n>, --format …) renders via the + // command layer. Bare /export keeps opening the export dialog. + if cmd == "export" && !args.trim().is_empty() { + if args.trim() == "copy" { + return self.intercept_slash_command("copy"); + } return false; } if cmd == "mcp" && !args.trim().is_empty() { @@ -2601,17 +2623,6 @@ impl App { self.should_exit = true; true } - "vim" => { - self.prompt_input.vim_enabled = !self.prompt_input.vim_enabled; - let status = if self.prompt_input.vim_enabled { - "enabled" - } else { - "disabled" - }; - self.status_message = Some(format!("Vim mode {}.", status)); - self.refresh_prompt_input(); - true - } "fast" => { self.fast_mode = !self.fast_mode; let status = if self.fast_mode { @@ -2693,47 +2704,10 @@ impl App { self.effort_picker.open(self.effort_level); true } - "voice" => { - let was_on = self.voice_recorder.is_some(); - if was_on { - // Stop any active recording before disabling. - if self.voice_recording { - self.voice_recording = false; - self.voice_event_rx = None; - if let Some(ref recorder_arc) = self.voice_recorder { - let recorder = recorder_arc.clone(); - tokio::task::spawn_blocking(move || { - if let Ok(mut r) = recorder.lock() { - tokio::runtime::Handle::current() - .block_on(r.stop_recording()) - .ok(); - } - }); - } - } - self.voice_recorder = None; - self.voice_mode_notice.dismiss(); - self.status_message = Some("Voice mode disabled.".to_string()); - } else { - let recorder = claurst_core::voice::global_voice_recorder(); - if let Ok(mut r) = recorder.lock() { - r.set_enabled(true); - } - self.voice_recorder = Some(recorder); - self.voice_mode_notice = crate::voice_mode_notice::VoiceModeNoticeState::new(); - self.status_message = - Some("Voice mode enabled. Press Alt+V to start recording.".to_string()); - } - true - } "doctor" => { // Handled by execute_command (DoctorCommand). false } - "cost" => { - self.stats_dialog.open(); - true - } "rewind" => { self.open_rewind_flow(); true @@ -2742,10 +2716,6 @@ impl App { self.export_dialog.open(); true } - "context" => { - self.context_viz.toggle(); - true - } "rename" => { self.session_browser.open(vec![]); self.session_list_pending = true; @@ -7681,16 +7651,6 @@ role = "Research" assert!(app.should_exit); } - #[test] - fn test_vim_slash_command_toggles_vim() { - let mut app = make_app(); - assert!(!app.prompt_input.vim_enabled); - assert!(app.intercept_slash_command("vim")); - assert!(app.prompt_input.vim_enabled); - assert!(app.intercept_slash_command("vim")); - assert!(!app.prompt_input.vim_enabled); - } - #[test] fn config_with_args_reaches_command_layer() { let mut app = make_app(); diff --git a/src-rust/crates/tui/src/lib.rs b/src-rust/crates/tui/src/lib.rs index a97f5edb..8be0172c 100644 --- a/src-rust/crates/tui/src/lib.rs +++ b/src-rust/crates/tui/src/lib.rs @@ -947,7 +947,7 @@ mod tests { .collect::<Vec<_>>() .join(""); - assert!(rendered.contains("/agents")); + assert!(rendered.contains("/agent")); assert!(rendered.contains("[cmd]")); }