feat(slash): fondation du système de commandes slash pour la CLI custom — #162 (QA verte)
Introduit le contrat unifié des commandes slash consommable par le frontend, indépendant de la source (native, puis plugin plus tard) : - domain: modèle pur SlashCommand / SlashCommandSource / SlashCommandAvailability, métadonnées UI (nom, description, disponibilité, confirmation requise) et validation des noms/préfixes. - application: registry + list/filter par préfixe + plan d'exécution natif ; commandes natives /help et /clean (/clean = nettoyage de la vue de session courante ; pas de /reset distinct tant qu'aucune utilité produit ne le justifie). - backend + app-tauri: exposition du contrat via DTO/transport + tests DTO. Source neutre : les commandes contribuées par plugins (#165) transiteront par le même registry sans changer le contrat frontend. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@ -93,6 +93,16 @@ impl ChatBridge {
|
||||
self.inner.scrollback(session)
|
||||
}
|
||||
|
||||
/// Clears only the retained conversation scrollback for a live session,
|
||||
/// keeping any currently attached channel in place.
|
||||
///
|
||||
/// Returns the number of chunks removed. This powers `/clean`: the frontend
|
||||
/// clears its mounted view from the command response, and future re-attaches
|
||||
/// no longer replay the old conversation.
|
||||
pub fn clear_scrollback(&self, session: &SessionId) -> usize {
|
||||
self.inner.clear_scrollback(session)
|
||||
}
|
||||
|
||||
/// Removes a session's transport state **and** its retained scrollback
|
||||
/// unconditionally (chat cell explicitly closed). Twin of
|
||||
/// [`PtyBridge::unregister`](crate::pty::PtyBridge::unregister).
|
||||
|
||||
@ -15,21 +15,23 @@ use application::{
|
||||
AppError, AssignSkillToAgentInput, AttachLiveAgentInput, ChangeAgentProfileInput,
|
||||
CloseProjectInput, CreateAgentInput, CreateLayoutInput, CreateMemoryInput, CreateSkillInput,
|
||||
DeleteAgentInput, DeleteEmbedderProfileInput, DeleteLayoutInput, DeleteMemoryInput,
|
||||
DeleteSkillInput, DeleteTemplateInput, DetectAgentDriftInput, GetMemoryInput,
|
||||
GetProjectSystemPermissionsInput, GetProjectWorkStateInput, GitBranchesInput, GitCheckoutInput,
|
||||
GitCommitInput, GitGraphInput, GitInitInput, GitLogInput, GitStagePathInput, GitStatusInput,
|
||||
InspectConversationInput, LaunchAgentInput, ListAgentsInput, ListDevicesInput,
|
||||
ListLayoutsInput, ListMemoriesInput, ListResumableAgentsInput, ListSkillsInput, LiveSessions,
|
||||
LoadLayoutInput, McpRuntime, MutateLayoutInput, OpenPluginLayoutWindowInput, OpenProjectInput,
|
||||
ReadAgentContextInput, ReadConversationPageInput, ReadMcpToolPermissionsInput,
|
||||
ReadMemoryIndexInput, ReadProjectContextInput, RecallMemoryInput, ReconcileLayoutsInput,
|
||||
ReconcileLiveStateInput, RenameDeviceInput, RenameLayoutInput, ResolveAgentPermissionsInput,
|
||||
DeleteSkillInput, DeleteTemplateInput, DetectAgentDriftInput, ExecuteSlashCommandInput,
|
||||
GetMemoryInput, GetProjectSystemPermissionsInput, GetProjectWorkStateInput, GitBranchesInput,
|
||||
GitCheckoutInput, GitCommitInput, GitGraphInput, GitInitInput, GitLogInput, GitStagePathInput,
|
||||
GitStatusInput, InspectConversationInput, LaunchAgentInput, ListAgentsInput, ListDevicesInput,
|
||||
ListLayoutsInput, ListMemoriesInput, ListResumableAgentsInput, ListSkillsInput,
|
||||
ListSlashCommandsInput, LiveSessions, LoadLayoutInput, McpRuntime, MutateLayoutInput,
|
||||
OpenPluginLayoutWindowInput, OpenProjectInput, ReadAgentContextInput,
|
||||
ReadConversationPageInput, ReadMcpToolPermissionsInput, ReadMemoryIndexInput,
|
||||
ReadProjectContextInput, RecallMemoryInput, ReconcileLayoutsInput, ReconcileLiveStateInput,
|
||||
RenameDeviceInput, RenameLayoutInput, ResolveAgentPermissionsInput,
|
||||
ResolveAgentSystemPermissionsInput, ResolveMemoryLinksInput, RevokeDeviceInput,
|
||||
RotateConversationLogInput, SetActiveLayoutInput, SnapshotRunningAgentsInput,
|
||||
StopLiveAgentInput, SyncAgentWithTemplateInput, UnassignSkillFromAgentInput,
|
||||
UpdateAgentContextInput, UpdateAgentEffortInput, UpdateAgentMcpToolPermissionsInput,
|
||||
UpdateAgentPermissionsInput, UpdateAgentSystemPermissionsInput, UpdateMemoryInput,
|
||||
UpdateProjectContextInput, UpdateProjectMcpToolPermissionsInput, UpdateProjectPermissionsInput,
|
||||
RotateConversationLogInput, SetActiveLayoutInput, SlashCommandEffect,
|
||||
SnapshotRunningAgentsInput, StopLiveAgentInput, SyncAgentWithTemplateInput,
|
||||
UnassignSkillFromAgentInput, UpdateAgentContextInput, UpdateAgentEffortInput,
|
||||
UpdateAgentMcpToolPermissionsInput, UpdateAgentPermissionsInput,
|
||||
UpdateAgentSystemPermissionsInput, UpdateMemoryInput, UpdateProjectContextInput,
|
||||
UpdateProjectMcpToolPermissionsInput, UpdateProjectPermissionsInput,
|
||||
UpdateProjectSystemPermissionsInput, UpdateSkillInput,
|
||||
};
|
||||
use backend::stream::OutputSink;
|
||||
@ -51,7 +53,8 @@ use crate::dto::{
|
||||
CreateProjectRequestDto, CreateSkillRequestDto, CreateTemplateRequestDto,
|
||||
DeleteLayoutRequestDto, DeleteLayoutResultDto, DeliveredDelegationRequestDto,
|
||||
DetectProfilesRequestDto, DetectProfilesResponseDto, EmbedderEnginesDto, EmbedderProfileDto,
|
||||
EmbedderProfileListDto, ErrorDto, FirstRunStateDto, FrontAttachedRequestDto, GitBranchesDto,
|
||||
EmbedderProfileListDto, ErrorDto, ExecuteSlashCommandRequestDto,
|
||||
ExecuteSlashCommandResponseDto, FirstRunStateDto, FrontAttachedRequestDto, GitBranchesDto,
|
||||
GitCheckoutRequestDto, GitCommitDto, GitCommitListDto, GitCommitRequestDto, GitStageRequestDto,
|
||||
GitStatusListDto, GraphCommitListDto, HealthRequestDto, HealthResponseDto,
|
||||
ImportChatAttachmentsRequestDto, ImportChatAttachmentsResponseDto,
|
||||
@ -68,12 +71,12 @@ use crate::dto::{
|
||||
ResolvedAgentSystemPermissionsDto, ResumableAgentListDto, SaveEmbedderProfileRequestDto,
|
||||
SaveModelServerRequestDto, SaveOpenCodeProviderProfileRequestDto, SaveProfileRequestDto,
|
||||
SetActiveLayoutRequestDto, SetActiveLayoutResultDto, SkillDto, SkillListDto,
|
||||
StopLiveAgentRequestDto, StopLiveAgentResponseDto, SyncAgentWithTemplateRequestDto,
|
||||
SyncResultDto, TemplateDto, TemplateListDto, TerminalClosedDto, TerminalSessionDto,
|
||||
TurnPageDto, UnassignSkillRequestDto, UpdateAgentContextRequestDto,
|
||||
UpdateAgentEffortRequestDto, UpdateAgentMcpToolPermissionsRequestDto,
|
||||
UpdateAgentPermissionsRequestDto, UpdateAgentSystemPermissionsRequestDto,
|
||||
UpdateMemoryRequestDto, UpdateProjectContextRequestDto,
|
||||
SlashCommandEffectDto, SlashCommandListDto, StopLiveAgentRequestDto, StopLiveAgentResponseDto,
|
||||
SyncAgentWithTemplateRequestDto, SyncResultDto, TemplateDto, TemplateListDto,
|
||||
TerminalClosedDto, TerminalSessionDto, TurnPageDto, UnassignSkillRequestDto,
|
||||
UpdateAgentContextRequestDto, UpdateAgentEffortRequestDto,
|
||||
UpdateAgentMcpToolPermissionsRequestDto, UpdateAgentPermissionsRequestDto,
|
||||
UpdateAgentSystemPermissionsRequestDto, UpdateMemoryRequestDto, UpdateProjectContextRequestDto,
|
||||
UpdateProjectMcpToolPermissionsRequestDto, UpdateProjectPermissionsRequestDto,
|
||||
UpdateProjectSystemPermissionsRequestDto, UpdateSkillRequestDto, UpdateTemplateRequestDto,
|
||||
WriteTerminalRequestDto,
|
||||
@ -105,6 +108,69 @@ pub fn health(
|
||||
.map_err(ErrorDto::from)
|
||||
}
|
||||
|
||||
/// `list_slash_commands` — list/filter the unified slash-command registry.
|
||||
#[tauri::command]
|
||||
pub fn list_slash_commands(
|
||||
request: Option<crate::dto::ListSlashCommandsRequestDto>,
|
||||
state: State<'_, AppState>,
|
||||
) -> SlashCommandListDto {
|
||||
let request = request.unwrap_or_default();
|
||||
state
|
||||
.list_slash_commands
|
||||
.execute(ListSlashCommandsInput {
|
||||
prefix: request.prefix,
|
||||
})
|
||||
.into()
|
||||
}
|
||||
|
||||
/// `execute_slash_command` — execute a selected slash command.
|
||||
///
|
||||
/// # Errors
|
||||
/// Returns an [`ErrorDto`] (`INVALID` for unavailable commands/missing context,
|
||||
/// `NOT_FOUND` for unknown commands or closed sessions).
|
||||
#[tauri::command]
|
||||
pub fn execute_slash_command(
|
||||
request: ExecuteSlashCommandRequestDto,
|
||||
state: State<'_, AppState>,
|
||||
) -> Result<ExecuteSlashCommandResponseDto, ErrorDto> {
|
||||
let session_id = request
|
||||
.session_id
|
||||
.as_deref()
|
||||
.map(parse_session_id)
|
||||
.transpose()?;
|
||||
let output = state
|
||||
.execute_slash_command
|
||||
.execute(ExecuteSlashCommandInput {
|
||||
name: request.name,
|
||||
session_id,
|
||||
})
|
||||
.map_err(ErrorDto::from)?;
|
||||
|
||||
let effect = match output.effect {
|
||||
SlashCommandEffect::Help { commands } => SlashCommandEffectDto::Help { commands },
|
||||
SlashCommandEffect::CleanConversation { session_id } => {
|
||||
if state.structured_sessions.session(&session_id).is_none() {
|
||||
return Err(ErrorDto::from(AppError::NotFound(format!(
|
||||
"structured session {session_id}"
|
||||
))));
|
||||
}
|
||||
let cleared_chunks = state.chat_bridge.clear_scrollback(&session_id);
|
||||
SlashCommandEffectDto::CleanConversation {
|
||||
session_id: session_id.to_string(),
|
||||
cleared_chunks,
|
||||
}
|
||||
}
|
||||
SlashCommandEffect::ProfileSwitch { session_id } => SlashCommandEffectDto::ProfileSwitch {
|
||||
session_id: session_id.to_string(),
|
||||
},
|
||||
};
|
||||
|
||||
Ok(ExecuteSlashCommandResponseDto {
|
||||
command: output.command,
|
||||
effect,
|
||||
})
|
||||
}
|
||||
|
||||
/// `get_server_exposure_settings` — read persisted embedded-server exposure settings.
|
||||
///
|
||||
/// # Errors
|
||||
|
||||
@ -248,6 +248,8 @@ pub fn run() {
|
||||
})
|
||||
.invoke_handler(tauri::generate_handler![
|
||||
commands::health,
|
||||
commands::list_slash_commands,
|
||||
commands::execute_slash_command,
|
||||
commands::create_project,
|
||||
commands::open_project,
|
||||
commands::close_project,
|
||||
|
||||
Reference in New Issue
Block a user