fix(skills): drive UI rename gating from server renamable flag

Expose authoritative renamable on skill list responses using the same
managed-root policy as renameSkill, drop the divergent UI path heuristic,
and remove an unused rejection-test fixture.

Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>
This commit is contained in:
Cursor Agent
2026-08-03 09:25:25 +00:00
co-authored by Serhii Dziupin
parent bfea13ef1d
commit 20fc675af0
10 changed files with 35 additions and 40 deletions
@@ -27,7 +27,6 @@ import { SidebarGroup } from '@/components/sections/shared/SidebarGroup';
import { Icon } from "@/components/icon/Icon";
import { useI18n } from '@/lib/i18n';
import { SETTINGS_PANEL_TITLE_CLASS } from '@/components/sections/shared/SettingsSection';
import { isManagedSkillFilesystemPath } from '@/components/sections/skills/skillLocations';
interface SkillsSidebarProps {
onItemSelect?: () => void;
@@ -37,7 +36,7 @@ const BUILT_IN_SKILL_LOCATION = '<built-in>';
const isBuiltInSkill = (skill: DiscoveredSkill | null | undefined): boolean => skill?.path === BUILT_IN_SKILL_LOCATION;
const isRenamableSkill = (skill: DiscoveredSkill | null | undefined): boolean => (
!!skill && !isBuiltInSkill(skill) && isManagedSkillFilesystemPath(skill.path)
!!skill && !isBuiltInSkill(skill) && skill.renamable === true
);
export const SkillsSidebar: React.FC<SkillsSidebarProps> = ({ onItemSelect }) => {
@@ -57,22 +57,3 @@ export function locationPartsFrom(value: SkillLocationValue): { scope: SkillScop
}
return { scope: match.scope, source: match.source };
}
/** True when a discovered skill path is under a managed skill root that rename/delete may mutate. */
export function isManagedSkillFilesystemPath(skillPath: string | null | undefined): boolean {
if (!skillPath || skillPath === '<built-in>') return false;
const normalized = skillPath.replace(/\\/g, '/');
if (
normalized.includes('/.cache/opencode/skills/')
|| normalized.includes('/Caches/opencode/skills/')
|| normalized.includes('/Library/Caches/opencode/skills/')
) {
return false;
}
return (
/\/\.opencode\/skills?\//.test(normalized)
|| /\/\.claude\/skills\//.test(normalized)
|| /\/\.agents\/skills\//.test(normalized)
|| /\/\.config\/opencode\/skills?\//.test(normalized)
);
}