diff --git a/PolyPilot.Tests/SlashCommandAutocompleteTests.cs b/PolyPilot.Tests/SlashCommandAutocompleteTests.cs
index 69ce546d1..a28ca692c 100644
--- a/PolyPilot.Tests/SlashCommandAutocompleteTests.cs
+++ b/PolyPilot.Tests/SlashCommandAutocompleteTests.cs
@@ -119,7 +119,7 @@ public void AutocompleteList_HasExpectedMinimumCommands()
var commands = GetAutocompleteCommands();
var expected = new[] { "/help", "/clear", "/compact", "/new", "/sessions",
"/rename", "/version", "/diff", "/status", "/mcp",
- "/plugin", "/reflect", "/usage" };
+ "/plugin", "/fleet", "/usage" };
foreach (var cmd in expected)
{
@@ -144,7 +144,7 @@ public void ParameterlessCommands_MarkedForAutoSend()
}
// Commands with args should have hasArgs: true
- var withArgs = new[] { "/new", "/rename", "/diff", "/reflect", "/mcp", "/plugin", "/prompt", "/status" };
+ var withArgs = new[] { "/new", "/rename", "/diff", "/fleet", "/mcp", "/plugin", "/prompt", "/status", "/agent" };
foreach (var cmd in withArgs)
{
var pattern = $"cmd: '{cmd}',";
diff --git a/PolyPilot/Components/ExpandedSessionView.razor b/PolyPilot/Components/ExpandedSessionView.razor
index f576599c4..a622656c9 100644
--- a/PolyPilot/Components/ExpandedSessionView.razor
+++ b/PolyPilot/Components/ExpandedSessionView.razor
@@ -264,10 +264,6 @@
- @if (Session.ReflectionCycle is null || !Session.ReflectionCycle.IsActive)
- {
-
- }
·
Log
·
@@ -282,6 +278,11 @@
·
@availableAgents.Count agents
}
+ @if (!string.IsNullOrEmpty(Session.ActiveAgentDisplayName ?? Session.ActiveAgentName))
+ {
+ ·
+ 🤖 @(Session.ActiveAgentDisplayName ?? Session.ActiveAgentName)
+ }
@if (availablePrompts != null)
{
·
@@ -1043,12 +1044,6 @@
");
}
- private async Task InsertReflectCommand()
- {
- var inputId = EscapeForJs("input-" + Session.Name.Replace(" ", "-"));
- await JS.InvokeVoidAsync("eval", $"var el = document.getElementById('{inputId}'); if(el){{ el.value = '/reflect '; el.focus(); }}");
- }
-
private static string EscapeForJs(string s) =>
s.Replace("\\", "\\\\").Replace("'", "\\'").Replace("\n", " ").Replace("\r", "")
.Replace("\u2028", "\\u2028").Replace("\u2029", "\\u2029");
diff --git a/PolyPilot/Components/ExpandedSessionView.razor.css b/PolyPilot/Components/ExpandedSessionView.razor.css
index 61c7e6b43..3f6812a21 100644
--- a/PolyPilot/Components/ExpandedSessionView.razor.css
+++ b/PolyPilot/Components/ExpandedSessionView.razor.css
@@ -682,6 +682,14 @@
cursor: pointer;
}
+.active-agent-badge {
+ font-size: var(--type-footnote);
+ color: var(--text-secondary, #888);
+ background: var(--hover-bg, rgba(124,92,252,0.08));
+ border-radius: 4px;
+ padding: 0 0.3rem;
+}
+
/* === Mobile responsive === */
@media (max-width: 640px) {
.status-extra { display: none; }
diff --git a/PolyPilot/Components/Pages/Dashboard.razor b/PolyPilot/Components/Pages/Dashboard.razor
index 9d9b815aa..2a954bcef 100644
--- a/PolyPilot/Components/Pages/Dashboard.razor
+++ b/PolyPilot/Components/Pages/Dashboard.razor
@@ -1804,9 +1804,10 @@
"- `/status` — Show git status\n" +
"- `/prompt` — List saved prompts (`/prompt use|save|edit|show|delete`)\n" +
"- `/usage` — Show token usage and quota for this session\n" +
+ "- `/agent [name]` — List or select a CLI agent\n" +
+ "- `/fleet ` — Start fleet mode (parallel subagent execution)\n" +
"- `/mcp` — List MCP servers (`/mcp enable|disable `, `/mcp reload` to restart)\n" +
"- `/plugin` — List installed plugins (enable/disable with `/plugin enable|disable `)\n" +
- "- `/reflect ` — Start a reflection cycle (`/reflect help` for details)\n" +
"- `!` — Run a shell command"));
break;
@@ -1815,6 +1816,10 @@
session.History.Add(ChatMessage.SystemMessage("Chat history cleared."));
break;
+ case "agent":
+ await HandleAgentCommand(session, sessionName, arg);
+ break;
+
case "version":
var appVersion = AppInfo.Current.VersionString;
var buildVersion = AppInfo.Current.BuildString;
@@ -1927,8 +1932,8 @@
HandlePluginCommand(session, arg);
break;
- case "reflect":
- await HandleReflectCommand(session, sessionName, arg);
+ case "fleet":
+ await HandleFleetCommand(session, sessionName, arg);
break;
case "prompt":
@@ -2153,136 +2158,72 @@
}
}
- private async Task HandleReflectCommand(AgentSessionInfo session, string sessionName, string arg)
+ private async Task HandleAgentCommand(AgentSessionInfo session, string sessionName, string arg)
{
- var subParts = arg.Split(' ', 2, StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries);
- var sub = subParts.Length > 0 ? subParts[0].ToLowerInvariant() : "";
-
- if (sub == "stop")
+ // /agent — list available agents
+ // /agent — select agent
+ // /agent deselect — deselect current agent
+ if (string.IsNullOrWhiteSpace(arg))
{
- CopilotService.StopReflectionCycle(sessionName);
- session.History.Add(ChatMessage.SystemMessage("🛑 Reflection cycle stopped."));
- return;
- }
+ // List agents from the API and from local discovery
+ var apiAgents = await CopilotService.ListAgentsFromApiAsync(sessionName);
+ var localAgents = CopilotService.DiscoverAvailableAgents(session.WorkingDirectory);
- if (sub == "pause")
- {
- if (session.ReflectionCycle is { IsActive: true, IsPaused: false })
- {
- session.ReflectionCycle.IsPaused = true;
- session.History.Add(ChatMessage.SystemMessage("⏸️ Reflection paused. Use `/reflect resume` to continue."));
- }
- else
- {
- session.History.Add(ChatMessage.ErrorMessage("No active reflection cycle to pause."));
- }
- return;
- }
+ var lines = new List { "**Available agents:**" };
- if (sub == "resume")
- {
- if (session.ReflectionCycle is { IsActive: true, IsPaused: true })
+ if (apiAgents.Count > 0)
{
- session.ReflectionCycle.IsPaused = false;
- session.ReflectionCycle.ResetStallDetection();
- session.History.Add(ChatMessage.SystemMessage("▶️ Reflection resumed."));
- // Re-queue a follow-up to continue the cycle
- var followUp = session.ReflectionCycle.BuildFollowUpPrompt("");
- if (session.IsProcessing)
- {
- session.MessageQueue.Add(followUp);
- }
- else
- {
- // Dispatch immediately if session is idle
- _ = CopilotService.SendPromptAsync(sessionName, followUp, skipHistoryMessage: true);
- }
+ lines.Add("*CLI agents:*");
+ foreach (var a in apiAgents)
+ lines.Add($"- `{a.Name}` — {a.Description}");
}
- else
- {
- session.History.Add(ChatMessage.ErrorMessage("No paused reflection cycle to resume."));
- }
- return;
- }
- if (sub == "status")
- {
- if (session.ReflectionCycle is { IsActive: true } rc)
+ if (localAgents.Count > 0)
{
- var status = rc.IsPaused ? "⏸️ Paused" : "🔄 Running";
- var evalInfo = !string.IsNullOrEmpty(rc.EvaluatorSessionName) ? "independent evaluator" : "self-evaluation";
- var feedback = !string.IsNullOrEmpty(rc.EvaluatorFeedback) ? $"\n**Last feedback:** {rc.EvaluatorFeedback}" : "";
- session.History.Add(ChatMessage.SystemMessage(
- $"{status} — **{rc.Goal}**\n" +
- $"Iteration {rc.CurrentIteration}/{rc.MaxIterations} · {evalInfo}{feedback}"));
+ lines.Add("*Local agents (from repo):*");
+ foreach (var a in localAgents)
+ lines.Add($"- `{a.Name}` — {a.Description}");
}
+
+ if (apiAgents.Count == 0 && localAgents.Count == 0)
+ lines.Add("No agents found. Try adding agent markdown files in `.github/agents/` or `.claude/agents/`.");
else
- {
- session.History.Add(ChatMessage.SystemMessage("No active reflection cycle."));
- }
- return;
- }
+ lines.Add("\nUse `/agent ` to select an agent, or `/agent deselect` to deselect.");
- if (string.IsNullOrWhiteSpace(arg) || sub == "help")
- {
- session.History.Add(ChatMessage.SystemMessage(
- "🔄 **Reflection Cycles** — Iterative goal-driven refinement\n\n" +
- "**Usage:**\n" +
- "```\n" +
- "/reflect Start a cycle (default 5 iterations)\n" +
- "/reflect --max N Set max iterations (default 5)\n" +
- "/reflect stop Cancel active cycle\n" +
- "/reflect pause Pause without cancelling\n" +
- "/reflect resume Resume paused cycle\n" +
- "/reflect status Show current cycle progress\n" +
- "/reflect help Show this help\n" +
- "```\n\n" +
- "**How it works:**\n" +
- "1. You set a goal → the worker starts iterating\n" +
- "2. After each response, an **independent evaluator** judges the result\n" +
- "3. If the evaluator says FAIL, its feedback is sent back to the worker\n" +
- "4. Cycle ends when: ✅ evaluator says PASS | ⚠️ stalled | ⏱️ max iterations\n\n" +
- "**Examples:**\n" +
- "```\n" +
- "/reflect write a haiku about rain --max 4\n" +
- "/reflect fix the login bug and add tests --max 8\n" +
- "/reflect refactor this function for readability\n" +
- "```\n\n" +
- "**Tips:**\n" +
- "- Send messages during a cycle to steer the worker\n" +
- "- Click the 🔄 pill in the header to stop\n" +
- "- The evaluator is strict early on, lenient on the final iteration"));
- return;
+ session.History.Add(ChatMessage.SystemMessage(string.Join("\n", lines)));
}
-
- // Parse --max N from the goal text (accept em-dash — which macOS auto-substitutes for --)
- int maxIterations = 5;
- var goal = arg;
- var maxMatch = System.Text.RegularExpressions.Regex.Match(arg, @"(?:--|—|\u2014)max\s+(\d+)");
- if (maxMatch.Success)
+ else if (string.Equals(arg, "deselect", StringComparison.OrdinalIgnoreCase))
{
- if (int.TryParse(maxMatch.Groups[1].Value, out var parsed) && parsed > 0)
- maxIterations = parsed;
- goal = arg.Remove(maxMatch.Index, maxMatch.Length).Trim();
+ var success = await CopilotService.DeselectAgentAsync(sessionName);
+ if (success)
+ session.History.Add(ChatMessage.SystemMessage("Agent deselected."));
+ else
+ session.History.Add(ChatMessage.ErrorMessage("Failed to deselect agent. Is the session connected?"));
}
-
- if (string.IsNullOrWhiteSpace(goal))
+ else
{
- session.History.Add(ChatMessage.ErrorMessage("Please provide a goal for the reflection cycle."));
- return;
+ var success = await CopilotService.SelectAgentAsync(sessionName, arg);
+ if (success)
+ session.History.Add(ChatMessage.SystemMessage($"Agent **{arg}** selected."));
+ else
+ session.History.Add(ChatMessage.ErrorMessage($"Failed to select agent '{arg}'. Is the agent name correct?"));
}
+ }
- await CopilotService.StartReflectionCycleAsync(sessionName, goal, maxIterations);
- session.History.Add(ChatMessage.SystemMessage($"🔄 Reflection cycle started — **{goal}** (max {maxIterations} iterations)"));
- if (session.IsProcessing)
+ private async Task HandleFleetCommand(AgentSessionInfo session, string sessionName, string arg)
+ {
+ if (string.IsNullOrWhiteSpace(arg))
{
- CopilotService.EnqueueMessage(sessionName, goal);
- session.History.Add(ChatMessage.SystemMessage("⏳ Current turn is still running — queued reflection goal to run next."));
+ session.History.Add(ChatMessage.SystemMessage(
+ "**Usage:** `/fleet `\n\nStarts fleet mode, which enables parallel subagent execution for the given prompt."));
return;
}
- // Send the goal as the initial prompt to kick off the first iteration
- _ = CopilotService.SendPromptAsync(sessionName, goal);
+ var started = await CopilotService.StartFleetAsync(sessionName, arg);
+ if (started)
+ session.History.Add(ChatMessage.SystemMessage($"🚀 Fleet started for: *{arg}*"));
+ else
+ session.History.Add(ChatMessage.ErrorMessage("Failed to start fleet mode. Ensure the session is connected and idle."));
}
private async Task HandlePromptCommand(string sessionName, AgentSessionInfo session, string arg)
diff --git a/PolyPilot/Models/AgentSessionInfo.cs b/PolyPilot/Models/AgentSessionInfo.cs
index 45bf1d407..88d9bb90a 100644
--- a/PolyPilot/Models/AgentSessionInfo.cs
+++ b/PolyPilot/Models/AgentSessionInfo.cs
@@ -205,6 +205,17 @@ public string? LastUserPrompt
///
public bool IsOrchestratorWorker { get; set; }
+ ///
+ /// The name of the CLI subagent currently active in this session (e.g. "code-review"),
+ /// or null if no subagent is active. Updated by SubagentSelectedEvent / SubagentDeselectedEvent.
+ ///
+ public string? ActiveAgentName { get; set; }
+
+ ///
+ /// Display name of the active subagent (e.g. "Code Review"), or null if none.
+ ///
+ public string? ActiveAgentDisplayName { get; set; }
+
internal static readonly string[] QuestionPhrases =
[
"let me know", "which would you prefer", "would you like", "should i", "do you want",
diff --git a/PolyPilot/Services/CopilotService.Events.cs b/PolyPilot/Services/CopilotService.Events.cs
index 9e8246f45..e9cf07c5e 100644
--- a/PolyPilot/Services/CopilotService.Events.cs
+++ b/PolyPilot/Services/CopilotService.Events.cs
@@ -54,11 +54,13 @@ private enum EventVisibility
["SessionCompactionCompleteEvent"] = EventVisibility.TimelineOnly,
["PendingMessagesModifiedEvent"] = EventVisibility.TimelineOnly,
["ToolUserRequestedEvent"] = EventVisibility.TimelineOnly,
- ["SkillInvokedEvent"] = EventVisibility.TimelineOnly,
- ["SubagentSelectedEvent"] = EventVisibility.TimelineOnly,
- ["SubagentStartedEvent"] = EventVisibility.TimelineOnly,
- ["SubagentCompletedEvent"] = EventVisibility.TimelineOnly,
- ["SubagentFailedEvent"] = EventVisibility.TimelineOnly,
+ ["SkillInvokedEvent"] = EventVisibility.ChatVisible,
+ ["SubagentSelectedEvent"] = EventVisibility.ChatVisible,
+ ["SubagentDeselectedEvent"] = EventVisibility.ChatVisible,
+ ["SubagentStartedEvent"] = EventVisibility.ChatVisible,
+ ["SubagentCompletedEvent"] = EventVisibility.ChatVisible,
+ ["SubagentFailedEvent"] = EventVisibility.ChatVisible,
+ ["CommandsChangedEvent"] = EventVisibility.TimelineOnly,
// Currently noisy internal events
["SessionLifecycleEvent"] = EventVisibility.Ignore,
@@ -827,7 +829,109 @@ await notifService.SendNotificationAsync(
Invoke(() => OnStateChanged?.Invoke());
}
break;
-
+
+ // ──────────────────────────────────────────────────────────────────────
+ // Subagent lifecycle: the CLI can automatically select specialized agents
+ // (e.g. code-review, security-review) when processing a prompt.
+ // Show these in chat so the user knows which agent is active.
+ // ──────────────────────────────────────────────────────────────────────
+ case SubagentSelectedEvent subagentSelected:
+ {
+ var d = subagentSelected.Data;
+ var displayName = !string.IsNullOrEmpty(d?.AgentDisplayName) ? d.AgentDisplayName : d?.AgentName;
+ if (!string.IsNullOrEmpty(displayName))
+ {
+ Invoke(() =>
+ {
+ state.Info.ActiveAgentName = d!.AgentName;
+ state.Info.ActiveAgentDisplayName = displayName;
+ state.Info.History.Add(ChatMessage.SystemMessage($"🤖 Agent: **{displayName}**"));
+ NotifyStateChangedCoalesced();
+ });
+ }
+ break;
+ }
+
+ case SubagentDeselectedEvent:
+ Invoke(() =>
+ {
+ state.Info.ActiveAgentName = null;
+ state.Info.ActiveAgentDisplayName = null;
+ NotifyStateChangedCoalesced();
+ });
+ break;
+
+ case SubagentStartedEvent subagentStarted:
+ {
+ var d = subagentStarted.Data;
+ var displayName = !string.IsNullOrEmpty(d?.AgentDisplayName) ? d.AgentDisplayName : d?.AgentName;
+ if (!string.IsNullOrEmpty(displayName))
+ {
+ var desc = !string.IsNullOrEmpty(d?.AgentDescription) ? $" — {d.AgentDescription}" : "";
+ Invoke(() =>
+ {
+ state.Info.History.Add(ChatMessage.SystemMessage($"▶️ Starting agent: **{displayName}**{desc}"));
+ NotifyStateChangedCoalesced();
+ });
+ }
+ break;
+ }
+
+ case SubagentCompletedEvent subagentCompleted:
+ {
+ var d = subagentCompleted.Data;
+ var displayName = !string.IsNullOrEmpty(d?.AgentDisplayName) ? d.AgentDisplayName : d?.AgentName;
+ Invoke(() =>
+ {
+ if (!string.IsNullOrEmpty(displayName))
+ state.Info.History.Add(ChatMessage.SystemMessage($"✅ Agent completed: **{displayName}**"));
+ // Always clear active agent state — even if displayName is empty
+ if (d?.AgentName == null || string.Equals(state.Info.ActiveAgentName, d.AgentName, StringComparison.OrdinalIgnoreCase))
+ {
+ state.Info.ActiveAgentName = null;
+ state.Info.ActiveAgentDisplayName = null;
+ }
+ NotifyStateChangedCoalesced();
+ });
+ break;
+ }
+
+ case SubagentFailedEvent subagentFailed:
+ {
+ var d = subagentFailed.Data;
+ var displayName = !string.IsNullOrEmpty(d?.AgentDisplayName) ? d.AgentDisplayName : d?.AgentName;
+ var errDetail = !string.IsNullOrEmpty(d?.Error) ? $": {d.Error}" : "";
+ Invoke(() =>
+ {
+ if (!string.IsNullOrEmpty(displayName))
+ state.Info.History.Add(ChatMessage.ErrorMessage($"Agent failed: **{displayName}**{errDetail}"));
+ // Always clear active agent state — even if displayName is empty
+ if (d?.AgentName == null || string.Equals(state.Info.ActiveAgentName, d.AgentName, StringComparison.OrdinalIgnoreCase))
+ {
+ state.Info.ActiveAgentName = null;
+ state.Info.ActiveAgentDisplayName = null;
+ }
+ NotifyStateChangedCoalesced();
+ });
+ break;
+ }
+
+ case SkillInvokedEvent skillInvoked:
+ {
+ var skillName = skillInvoked.Data?.Name;
+ var pluginName = skillInvoked.Data?.PluginName;
+ var label = !string.IsNullOrEmpty(pluginName) ? $"{skillName} ({pluginName})" : skillName;
+ if (!string.IsNullOrEmpty(label))
+ {
+ Invoke(() =>
+ {
+ state.Info.History.Add(ChatMessage.SystemMessage($"⚡ Skill: **{label}**"));
+ NotifyStateChangedCoalesced();
+ });
+ }
+ break;
+ }
+
default:
LogUnhandledSessionEvent(sessionName, evt);
break;
@@ -1406,7 +1510,7 @@ private void HandleReflectionAdvanceResult(SessionState state, string response,
var ctxPct = (double)state.Info.ContextCurrentTokens.Value / state.Info.ContextTokenLimit.Value;
if (ctxPct > 0.9)
{
- var ctxWarning = ChatMessage.SystemMessage($"🔴 Context {ctxPct:P0} full — reflection may lose earlier history. Consider `/reflect stop`.");
+ var ctxWarning = ChatMessage.SystemMessage($"🔴 Context {ctxPct:P0} full — reflection may lose earlier history.");
state.Info.History.Add(ctxWarning);
state.Info.MessageCount = state.Info.History.Count;
if (!string.IsNullOrEmpty(state.Info.SessionId))
diff --git a/PolyPilot/Services/CopilotService.cs b/PolyPilot/Services/CopilotService.cs
index 7dc691855..d9aed2478 100644
--- a/PolyPilot/Services/CopilotService.cs
+++ b/PolyPilot/Services/CopilotService.cs
@@ -1906,6 +1906,99 @@ public List DiscoverAvailableAgents(string? workingDirectory)
return agents;
}
+ ///
+ /// Lists agents available in the current session via the SDK AgentApi.
+ /// Returns an empty list if the session doesn't exist, is not connected, or the API fails.
+ ///
+ public async Task> ListAgentsFromApiAsync(string sessionName)
+ {
+ if (!_sessions.TryGetValue(sessionName, out var state) || state.Session == null)
+ return [];
+
+ try
+ {
+ var result = await state.Session.Rpc.Agent.ListAsync(CancellationToken.None);
+ return result?.Agents?
+ .Where(a => !string.IsNullOrEmpty(a?.Name))
+ .Select(a => new AgentInfo(
+ a!.Name!,
+ a.Description ?? a.DisplayName ?? "",
+ "cli"))
+ .ToList() ?? [];
+ }
+ catch (Exception ex)
+ {
+ System.Diagnostics.Debug.WriteLine($"[Agents] ListAsync failed for '{sessionName}': {ex.Message}");
+ return [];
+ }
+ }
+
+ ///
+ /// Selects a CLI agent for the given session via the SDK AgentApi.
+ /// Returns true on success, false on error.
+ ///
+ public async Task SelectAgentAsync(string sessionName, string agentName)
+ {
+ if (!_sessions.TryGetValue(sessionName, out var state) || state.Session == null)
+ return false;
+
+ try
+ {
+ await state.Session.Rpc.Agent.SelectAsync(agentName, CancellationToken.None);
+ return true;
+ }
+ catch (Exception ex)
+ {
+ System.Diagnostics.Debug.WriteLine($"[Agents] SelectAsync('{agentName}') failed for '{sessionName}': {ex.Message}");
+ return false;
+ }
+ }
+
+ ///
+ /// Deselects the active CLI agent for the given session.
+ /// Returns true on success, false on error.
+ ///
+ public async Task DeselectAgentAsync(string sessionName)
+ {
+ if (!_sessions.TryGetValue(sessionName, out var state) || state.Session == null)
+ return false;
+
+ try
+ {
+ await state.Session.Rpc.Agent.DeselectAsync(CancellationToken.None);
+ return true;
+ }
+ catch (Exception ex)
+ {
+ System.Diagnostics.Debug.WriteLine($"[Agents] DeselectAsync failed for '{sessionName}': {ex.Message}");
+ return false;
+ }
+ }
+
+ ///
+ /// Starts fleet mode (parallel subagent execution) for the given session with the provided prompt.
+ /// Returns true if the fleet was started successfully, false otherwise.
+ ///
+ public async Task StartFleetAsync(string sessionName, string prompt)
+ {
+ if (!_sessions.TryGetValue(sessionName, out var state) || state.Session == null)
+ return false;
+
+ if (state.Info.IsProcessing)
+ return false;
+
+ try
+ {
+ var result = await state.Session.Rpc.Fleet.StartAsync(prompt, CancellationToken.None);
+ return result?.Started ?? false;
+ }
+ catch (Exception ex)
+ {
+ System.Diagnostics.Debug.WriteLine($"[Fleet] StartAsync failed for '{sessionName}': {ex.Message}");
+ return false;
+ }
+ }
+
private static void ScanAgentDirectory(string agentsDir, string source, List agents, HashSet seen)
{
foreach (var file in Directory.GetFiles(agentsDir, "*.md"))
diff --git a/PolyPilot/wwwroot/index.html b/PolyPilot/wwwroot/index.html
index b3a2ef739..28203829b 100644
--- a/PolyPilot/wwwroot/index.html
+++ b/PolyPilot/wwwroot/index.html
@@ -759,15 +759,16 @@
window.__slashCmdSetup = true;
var COMMANDS = [
+ { cmd: '/agent', usage: '[name]', desc: 'List or select a CLI agent', hasArgs: true },
{ cmd: '/clear', desc: 'Clear chat history', hasArgs: false },
{ cmd: '/compact', desc: 'Summarize conversation', hasArgs: false },
{ cmd: '/diff', usage: '[args]', desc: 'Show git diff', hasArgs: true },
+ { cmd: '/fleet', usage: '', desc: 'Start fleet mode (parallel subagent execution)', hasArgs: true },
{ cmd: '/help', desc: 'Show available commands', hasArgs: false },
{ cmd: '/mcp', usage: '[show|add|edit|delete|disable|enable] [server-name] | reload', desc: 'Manage MCP servers', hasArgs: true },
{ cmd: '/new', usage: '[name]', desc: 'Create a new session', hasArgs: true },
{ cmd: '/plugin', usage: '[enable|disable] [plugin-name]', desc: 'Manage installed plugins', hasArgs: true },
{ cmd: '/prompt', usage: '[use|save|delete] [name]', desc: 'List saved prompts', hasArgs: true },
- { cmd: '/reflect', usage: '', desc: 'Start a reflection cycle', hasArgs: true },
{ cmd: '/rename', usage: '', desc: 'Rename current session', hasArgs: true },
{ cmd: '/sessions', desc: 'List all sessions', hasArgs: false },
{ cmd: '/status', usage: '[path] [--short]', desc: 'Show git status', hasArgs: true },