import type { SkillInfo, SkillVisibilityScope } from './types'; import { syncSkillMarkdownFrontmatter } from './skill-markdown'; /** Build a hidden, standards-compliant canonical name for a new Skill. */ export function createSkillCanonicalName( displayName: string, suffix = createRandomSuffix(), ): string { const slug = displayName .normalize('NFKD') .toLowerCase() .replaceAll(/[^a-z0-9]+/g, '-') .replaceAll(/^-+|-+$/g, '') .slice(0, 48) .replaceAll(/-+$/g, ''); const prefix = slug || 'skill'; return `${prefix}-${suffix}`.slice(0, 64).replaceAll(/-+$/g, ''); } /** Create the minimal valid package accepted by the Skill draft endpoint. */ export function buildInitialSkillDraft(input: { categoryId?: number | string; displayName: string; visibilityScope: SkillVisibilityScope; }): SkillInfo { const displayName = input.displayName.trim(); const name = createSkillCanonicalName(displayName); const content = syncSkillMarkdownFrontmatter( '# Instructions\n\n', name, displayName, ); return { categoryId: input.categoryId || undefined, description: displayName, displayName, name, publishStatus: 'DRAFT', skillContent: content, visibilityScope: input.visibilityScope, }; } function createRandomSuffix() { const uuid = globalThis.crypto?.randomUUID?.().replaceAll('-', ''); if (uuid) return uuid.slice(0, 10); return Math.random().toString(36).slice(2, 12).padEnd(10, '0'); }