feat(chat): align command, shell, and subtask UX (#444)

* feat: reload interface after skills operations

- Adds configurable delay before interface reload after skills changes
- Introduces polling to wait for application health after reload
- Updates UI to show reload message when installing or modifying skills

* feat: distinguish skills from commands in UI

- Displays skill badge for commands that are registered skills
- Prevents editing skills through command management interface
- Triggers interface reload after skill operations to reflect changes

* feat(chat): align command and subtask UX with opencode parity

Route commands/shell via parity paths, render delegated subtasks cleanly, and surface child-session permission/question prompts in parent chat.

* fix(ProjectEditDialog): improve layout consistency

* fix: update task icon and session handling in ToolPart

* feat(chat): add shell-mode input and collapse shell bridge output

Switch leading ! to shell mode UX and fold synthetic shell bridge assistant messages into the user shell bubble with inline output actions.

* fix: remove AI agent icon from file mention autocomplete

* fix: remove unused icon import from file mention component
This commit is contained in:
Bohdan Triapitsyn
2026-02-18 20:08:42 +02:00
committed by GitHub
parent e4a2486312
commit 85f21cb945
23 changed files with 1557 additions and 318 deletions
+3 -3
View File
@@ -335,7 +335,7 @@ export const useSessionStore = create<SessionStore>()(
get().evictLeastRecentlyUsed();
},
loadMessages: (sessionId: string, limit?: number) => useMessageStore.getState().loadMessages(sessionId, limit),
sendMessage: async (content: string, providerID: string, modelID: string, agent?: string, attachments?: AttachedFile[], agentMentionName?: string, additionalParts?: Array<{ text: string; attachments?: AttachedFile[]; synthetic?: boolean }>, variant?: string) => {
sendMessage: async (content: string, providerID: string, modelID: string, agent?: string, attachments?: AttachedFile[], agentMentionName?: string, additionalParts?: Array<{ text: string; attachments?: AttachedFile[]; synthetic?: boolean }>, variant?: string, inputMode: 'normal' | 'shell' = 'normal') => {
const draft = get().newSessionDraft;
const trimmedAgent = typeof agent === 'string' && agent.trim().length > 0 ? agent.trim() : undefined;
@@ -420,7 +420,7 @@ export const useSessionStore = create<SessionStore>()(
try {
return await useMessageStore
.getState()
.sendMessage(content, providerID, modelID, effectiveDraftAgent, created.id, attachments, agentMentionName, mergedAdditionalParts, variant);
.sendMessage(content, providerID, modelID, effectiveDraftAgent, created.id, attachments, agentMentionName, mergedAdditionalParts, variant, inputMode);
} catch (error) {
setStatus(created.id, 'idle');
throw error;
@@ -477,7 +477,7 @@ export const useSessionStore = create<SessionStore>()(
}
try {
return await useMessageStore.getState().sendMessage(content, providerID, modelID, effectiveAgent, currentSessionId || undefined, attachments, agentMentionName, additionalParts, variant);
return await useMessageStore.getState().sendMessage(content, providerID, modelID, effectiveAgent, currentSessionId || undefined, attachments, agentMentionName, additionalParts, variant, inputMode);
} catch (error) {
if (currentSessionId) {
setStatus(currentSessionId, 'idle');