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:
committed by
GitHub
parent
e4a2486312
commit
85f21cb945
@@ -3,6 +3,7 @@ import { RiCommandLine, RiFileLine, RiFlashlightLine, RiRefreshLine, RiScissorsL
|
||||
import { cn, fuzzyMatch } from '@/lib/utils';
|
||||
import { useSessionStore } from '@/stores/useSessionStore';
|
||||
import { useCommandsStore } from '@/stores/useCommandsStore';
|
||||
import { useSkillsStore } from '@/stores/useSkillsStore';
|
||||
import { useShallow } from 'zustand/react/shallow';
|
||||
import { ScrollableOverlay } from '@/components/ui/ScrollableOverlay';
|
||||
|
||||
@@ -12,6 +13,7 @@ interface CommandInfo {
|
||||
agent?: string;
|
||||
model?: string;
|
||||
isBuiltIn?: boolean;
|
||||
isSkill?: boolean;
|
||||
scope?: string;
|
||||
}
|
||||
|
||||
@@ -53,6 +55,7 @@ export const CommandAutocomplete = React.forwardRef<CommandAutocompleteHandle, C
|
||||
const [commands, setCommands] = React.useState<CommandInfo[]>([]);
|
||||
const [loading, setLoading] = React.useState(false);
|
||||
const { commands: commandsWithMetadata, loadCommands: refreshCommands } = useCommandsStore();
|
||||
const { skills, loadSkills: refreshSkills } = useSkillsStore();
|
||||
const [selectedIndex, setSelectedIndex] = React.useState(0);
|
||||
const itemRefs = React.useRef<(HTMLDivElement | null)[]>([]);
|
||||
const containerRef = React.useRef<HTMLDivElement | null>(null);
|
||||
@@ -82,18 +85,21 @@ export const CommandAutocomplete = React.forwardRef<CommandAutocompleteHandle, C
|
||||
React.useEffect(() => {
|
||||
// Force refresh to get latest project context when mounting
|
||||
void refreshCommands();
|
||||
}, [refreshCommands]);
|
||||
void refreshSkills();
|
||||
}, [refreshCommands, refreshSkills]);
|
||||
|
||||
React.useEffect(() => {
|
||||
const loadCommands = async () => {
|
||||
setLoading(true);
|
||||
try {
|
||||
const skillNames = new Set(skills.map((skill) => skill.name));
|
||||
const customCommands: CommandInfo[] = commandsWithMetadata.map(cmd => ({
|
||||
name: cmd.name,
|
||||
description: cmd.description,
|
||||
agent: cmd.agent ?? undefined,
|
||||
model: cmd.model ?? undefined,
|
||||
isBuiltIn: cmd.name === 'init' || cmd.name === 'review',
|
||||
isSkill: skillNames.has(cmd.name),
|
||||
scope: cmd.scope,
|
||||
}));
|
||||
|
||||
@@ -171,7 +177,7 @@ export const CommandAutocomplete = React.forwardRef<CommandAutocompleteHandle, C
|
||||
};
|
||||
|
||||
loadCommands();
|
||||
}, [searchQuery, hasMessagesInCurrentSession, hasSession, commandsWithMetadata]);
|
||||
}, [searchQuery, hasMessagesInCurrentSession, hasSession, commandsWithMetadata, skills]);
|
||||
|
||||
React.useEffect(() => {
|
||||
setSelectedIndex(0);
|
||||
@@ -356,6 +362,11 @@ export const CommandAutocomplete = React.forwardRef<CommandAutocompleteHandle, C
|
||||
<div className="flex-1 min-w-0">
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="typography-ui-label font-medium">/{command.name}</span>
|
||||
{command.isSkill ? (
|
||||
<span className="text-[10px] leading-none uppercase font-bold tracking-tight bg-[var(--status-info-background)] text-[var(--status-info)] border-[var(--status-info-border)] px-1.5 py-1 rounded border flex-shrink-0">
|
||||
skill
|
||||
</span>
|
||||
) : null}
|
||||
{isSystem ? (
|
||||
<span className="text-[10px] leading-none uppercase font-bold tracking-tight bg-[var(--status-warning-background)] text-[var(--status-warning)] border-[var(--status-warning-border)] px-1.5 py-1 rounded border flex-shrink-0">
|
||||
system
|
||||
|
||||
Reference in New Issue
Block a user