fix: use opencode skills as source of truth

This commit is contained in:
Bohdan Triapitsyn
2026-05-17 14:51:25 +03:00
parent 8900b8f0f2
commit bbc297202e
20 changed files with 384 additions and 101 deletions
@@ -18,6 +18,7 @@ import { isExpandableTool, isStandaloneTool, isStaticTool } from './toolRenderUt
import { RuntimeAPIContext } from '@/contexts/runtimeAPIContext';
import { useDirectoryStore } from '@/stores/useDirectoryStore';
import { useUIStore } from '@/stores/useUIStore';
import { useSkillsStore } from '@/stores/useSkillsStore';
import ReasoningPart from './ReasoningPart';
import JustificationBlock from './JustificationBlock';
import { areRenderRelevantPartsEqual } from '../renderCompare';
@@ -599,7 +600,9 @@ const StaticToolRowInner: React.FC<{
const isReadGroup = toolName.toLowerCase() === 'read';
const runtime = React.useContext(RuntimeAPIContext);
const currentDirectory = useDirectoryStore((state) => state.currentDirectory);
const skills = useSkillsStore((state) => state.skills);
const hasRunningActivity = React.useMemo(() => activities.some((activity) => isActivityRunning(activity)), [activities]);
const skillByName = React.useMemo(() => new Map(skills.map((skill) => [skill.name, skill])), [skills]);
const descriptions = React.useMemo(() => {
const descs: string[] = [];
@@ -648,6 +651,15 @@ const StaticToolRowInner: React.FC<{
uiStore.openContextFile(contextDirectory, absolutePath);
}, [currentDirectory, runtime]);
const handleSkillClick = React.useCallback((skillName: string) => {
const skill = skillByName.get(skillName);
if (!skill?.path) {
return;
}
const uiStore = useUIStore.getState();
uiStore.openContextFile(currentDirectory || getContextDirectoryForPath('', skill.path), skill.path);
}, [currentDirectory, skillByName]);
const normalizedToolName = toolName.toLowerCase();
const isSearchGroup = normalizedToolName === 'grep'
|| normalizedToolName === 'search'
@@ -655,6 +667,7 @@ const StaticToolRowInner: React.FC<{
|| normalizedToolName === 'ripgrep'
|| normalizedToolName === 'glob';
const isFetchGroup = normalizedToolName === 'webfetch' || normalizedToolName === 'fetch' || normalizedToolName === 'curl' || normalizedToolName === 'wget';
const isSkillGroup = normalizedToolName === 'skill';
return (
<div
@@ -725,7 +738,25 @@ const StaticToolRowInner: React.FC<{
</a>
))
: null}
{!isReadGroup && !isSearchGroup && !isFetchGroup && descriptions.length > 0 ? (
{isSkillGroup && descriptions.length > 0
? descriptions.map((skillName, index) => (
<button
key={`${skillName}-${index}`}
type="button"
onClick={(event) => {
event.preventDefault();
event.stopPropagation();
handleSkillClick(skillName);
}}
className="min-w-0 flex-1 truncate whitespace-nowrap typography-meta leading-5 text-left hover:opacity-90"
style={{ color: 'var(--tools-description)' }}
title={skillName}
>
{skillName}
</button>
))
: null}
{!isReadGroup && !isSearchGroup && !isFetchGroup && !isSkillGroup && descriptions.length > 0 ? (
<Text
variant={animateTailText ? 'generate-effect' : 'static'}
className="min-w-0 flex-1 truncate whitespace-nowrap typography-meta leading-5"