41 lines
1.8 KiB
JavaScript
41 lines
1.8 KiB
JavaScript
"use strict";
|
|
// =============================================================================
|
|
// Pure skills API. Skills live in a Gitea repo at .skills/<name>/SKILL.md.
|
|
// Takes a GiteaReadConfig so it can read from any Gitea instance (in-process
|
|
// agent passes ctx.gitea, MCP server loads from env).
|
|
// =============================================================================
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
exports.listSkills = listSkills;
|
|
exports.getSkill = getSkill;
|
|
const SKILL_FILE = 'SKILL.md';
|
|
const SKILLS_DIR = '.skills';
|
|
async function giteaGetContents(cfg, repo, filePath) {
|
|
const res = await fetch(`${cfg.apiUrl}/api/v1/repos/${repo}/contents/${filePath}`, {
|
|
headers: { Authorization: `token ${cfg.apiToken}` },
|
|
});
|
|
if (!res.ok)
|
|
return null;
|
|
return res.json();
|
|
}
|
|
async function listSkills(cfg, repo) {
|
|
const contents = await giteaGetContents(cfg, repo, SKILLS_DIR);
|
|
if (!contents || !Array.isArray(contents)) {
|
|
return { skills: [], message: `No .skills/ directory found in ${repo}` };
|
|
}
|
|
const skills = contents
|
|
.filter((entry) => entry.type === 'dir')
|
|
.map((entry) => ({ name: entry.name, path: entry.path }));
|
|
return { repo, skills };
|
|
}
|
|
async function getSkill(cfg, repo, skillName) {
|
|
const filePath = `${SKILLS_DIR}/${skillName}/${SKILL_FILE}`;
|
|
const file = await giteaGetContents(cfg, repo, filePath);
|
|
if (!file || !file.content) {
|
|
return { error: `Skill "${skillName}" not found in ${repo}. Try list_skills to see available skills.` };
|
|
}
|
|
const content = Buffer.from(file.content, 'base64').toString('utf8');
|
|
// Strip YAML frontmatter if present, return just the markdown body
|
|
const body = content.replace(/^---[\s\S]*?---\s*/m, '').trim();
|
|
return { repo, skill: skillName, content: body };
|
|
}
|