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:
co-authored by
Serhii Dziupin
parent
bfea13ef1d
commit
20fc675af0
@@ -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)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -70,6 +70,8 @@ export interface DiscoveredSkill {
|
||||
description?: string;
|
||||
/** Domain folder parsed from file path, e.g. "automation-ai", "lark-ecosystem" */
|
||||
group?: string;
|
||||
/** Authoritative server flag: skill lives under a managed root and can be renamed in place. */
|
||||
renamable?: boolean;
|
||||
}
|
||||
|
||||
/** Parse the domain group folder from a skill file path.
|
||||
@@ -93,6 +95,7 @@ interface RawSkillResponse {
|
||||
path: string;
|
||||
scope?: SkillScope;
|
||||
source?: SkillSource;
|
||||
renamable?: boolean;
|
||||
sources?: {
|
||||
md?: {
|
||||
description?: string;
|
||||
@@ -237,6 +240,7 @@ export const useSkillsStore = create<SkillsStore>()(
|
||||
source: s.source ?? 'opencode',
|
||||
description: s.sources?.md?.description || '',
|
||||
group: parseSkillGroup(s.path),
|
||||
renamable: s.renamable === true,
|
||||
}));
|
||||
|
||||
set({ skills: configSkills, isLoading: false });
|
||||
|
||||
Reference in New Issue
Block a user