Files
doormilxpress_astryx/src/lib/skills/customSkills.js

79 lines
2.3 KiB
JavaScript

import { parseSkill } from './registry';
/**
* Account-authored skills, as stored.
*
* A custom skill is its Markdown source and nothing else — the same artefact a
* file in `src/skills/` is, read back by the same parser. These helpers exist so
* the Add Skill dialog and the Skills page write that list identically; two
* writers with two shapes would be a second skill system by accident.
*/
/** The starting definition offered to an author, in the existing format. */
export const skillTemplate = ({ id = '', name = '', description = '', pages = [] } = {}) => `---
id: ${id || 'my-skill'}
name: ${name || 'My Skill'}
description: ${description || 'What this skill helps Owliver do.'}
pages:
${(pages?.length ? pages : ['positions']).map((p) => ` - ${p}`).join('\n')}
status: active
triggers:
- ${(name || 'my skill').toLowerCase()}
---
# ${name || 'My Skill'}
## Purpose
Describe what Owliver should help with on these pages.
## Capabilities
- Describe one thing the skill can do.
- Add more as needed.
`;
/** Parses a stored entry, tolerating the bare-string form. */
const sourceOf = (entry) => (typeof entry === 'string' ? entry : entry?.raw ?? '');
/**
* The stored list with `source` added or replaced.
*
* Matching is by skill id, so editing a skill overwrites its own entry rather
* than adding a near-duplicate beside it.
*/
export function upsertCustomSkill(existing = [], source) {
const skill = parseSkill(source, { custom: true });
const rest = existing.filter((entry) => {
try {
return parseSkill(sourceOf(entry), { custom: true }).id !== skill.id;
} catch {
return true;
}
});
return { skill, next: [...rest, { path: `custom/${skill.id}.md`, raw: source }] };
}
/** The stored list without the skill of this id. */
export function removeCustomSkill(existing = [], id) {
return existing.filter((entry) => {
try {
return parseSkill(sourceOf(entry), { custom: true }).id !== id;
} catch {
return true;
}
});
}
/** The stored Markdown for one custom skill, or null if the account has none. */
export function customSkillSource(existing = [], id) {
for (const entry of existing) {
try {
if (parseSkill(sourceOf(entry), { custom: true }).id === id) return sourceOf(entry);
} catch {
/* An unparseable entry cannot be the one being edited. */
}
}
return null;
}