mirror of
https://github.com/siteboon/claudecodeui.git
synced 2026-07-05 21:13:00 +08:00
fix(skills): validate installs before writing
Preserve bundled files and normalize fallback names across skill installation paths. Validate complete batches before writing and reject existing targets to avoid partial installs. Keep project metadata and make folder selection tolerant of casing and cancelled dialogs.
This commit is contained in:
@@ -111,8 +111,12 @@ const normalizeSkill = (
|
||||
sourcePath: String(skill.sourcePath ?? ''),
|
||||
pluginName: typeof skill.pluginName === 'string' ? skill.pluginName : undefined,
|
||||
pluginId: typeof skill.pluginId === 'string' ? skill.pluginId : undefined,
|
||||
projectDisplayName: shouldAttachProject ? project?.displayName : undefined,
|
||||
projectPath: shouldAttachProject ? project?.path : undefined,
|
||||
projectDisplayName: shouldAttachProject
|
||||
? project?.displayName ?? skill.projectDisplayName
|
||||
: skill.projectDisplayName,
|
||||
projectPath: shouldAttachProject
|
||||
? project?.path ?? skill.projectPath
|
||||
: skill.projectPath,
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -170,14 +170,18 @@ const buildQueuedSkillFolders = (selectedFiles: File[]): QueuedSkillFile[] => {
|
||||
|
||||
return skillRoots.map((skillRoot) => {
|
||||
const skillFiles = files.filter(({ relativePath }) => {
|
||||
const owningRoot = skillRoots.find((candidateRoot) => (
|
||||
relativePath === `${candidateRoot}/SKILL.md`
|
||||
|| relativePath.startsWith(`${candidateRoot}/`)
|
||||
));
|
||||
const owningRoot = skillRoots.find((candidateRoot) => {
|
||||
const normalizedRelativePath = relativePath.toLowerCase();
|
||||
const normalizedSkillPath = `${candidateRoot}/skill.md`.toLowerCase();
|
||||
return normalizedRelativePath === normalizedSkillPath
|
||||
|| relativePath.startsWith(`${candidateRoot}/`);
|
||||
});
|
||||
return owningRoot === skillRoot;
|
||||
});
|
||||
const skillSourceFile = skillFiles.find(
|
||||
({ relativePath }) => relativePath === `${skillRoot}/SKILL.md`,
|
||||
({ relativePath }) => (
|
||||
relativePath.toLowerCase() === `${skillRoot}/skill.md`.toLowerCase()
|
||||
),
|
||||
);
|
||||
if (!skillSourceFile) {
|
||||
throw new Error(`Could not read SKILL.md from ${getBaseName(skillRoot)}.`);
|
||||
@@ -303,6 +307,10 @@ export default function ProviderSkills({ selectedProvider, currentProjects }: Pr
|
||||
}, [queueSkillFolders]);
|
||||
|
||||
const handleFolderSelection = useCallback((selectedFiles: File[]) => {
|
||||
if (selectedFiles.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
queueSkillFolders(selectedFiles);
|
||||
setSubmitError(null);
|
||||
|
||||
Reference in New Issue
Block a user