50 lines
1.4 KiB
TypeScript
50 lines
1.4 KiB
TypeScript
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');
|
|
}
|