/**
* Skill Installer
* スキルのインストール・アンインストール処理
*/
import * as fs from "fs/promises";
import * as path from "path";
/** インストール結果 */
export interface InstallResult {
success: boolean;
skillName: string;
installPath: string;
message: string;
}
/**
* スキルをワークスペースにインストール
*/
export async function installSkill(
skillName: string,
skillContent: string,
workspacePath: string
): Promise<InstallResult> {
const skillsDir = path.join(workspacePath, ".github", "skills", skillName);
const skillFilePath = path.join(skillsDir, "SKILL.md");
try {
// ディレクトリを作成
await fs.mkdir(skillsDir, { recursive: true });
// SKILL.md を書き込み
await fs.writeFile(skillFilePath, skillContent, "utf-8");
return {
success: true,
skillName,
installPath: skillsDir,
message: `Successfully installed ${skillName}`,
};
} catch (error) {
return {
success: false,
skillName,
installPath: skillsDir,
message: `Failed to install ${skillName}: ${error}`,
};
}
}
/**
* スキルをアンインストール
*/
export async function uninstallSkill(
skillName: string,
workspacePath: string
): Promise<InstallResult> {
const skillsDir = path.join(workspacePath, ".github", "skills", skillName);
try {
// ディレクトリを削除
await fs.rm(skillsDir, { recursive: true, force: true });
return {
success: true,
skillName,
installPath: skillsDir,
message: `Successfully uninstalled ${skillName}`,
};
} catch (error) {
return {
success: false,
skillName,
installPath: skillsDir,
message: `Failed to uninstall ${skillName}: ${error}`,
};
}
}
/**
* インストール済みスキル一覧を取得
*/
export async function getInstalledSkills(
workspacePath: string
): Promise<string[]> {
const skillsDir = path.join(workspacePath, ".github", "skills");
try {
const entries = await fs.readdir(skillsDir, { withFileTypes: true });
const skills: string[] = [];
for (const entry of entries) {
if (entry.isDirectory()) {
// SKILL.md が存在するか確認
const skillFile = path.join(skillsDir, entry.name, "SKILL.md");
try {
await fs.access(skillFile);
skills.push(entry.name);
} catch {
// SKILL.md がなければスキップ
}
}
}
return skills;
} catch {
// ディレクトリが存在しない場合は空配列
return [];
}
}
/**
* AGENTS.md を更新
*/
export async function updateAgentsMd(workspacePath: string): Promise<void> {
const agentsPath = path.join(workspacePath, "AGENTS.md");
const installedSkills = await getInstalledSkills(workspacePath);
if (installedSkills.length === 0) {
// スキルがない場合は AGENTS.md を削除
try {
await fs.unlink(agentsPath);
} catch {
// 存在しなければ無視
}
return;
}
// AGENTS.md の内容を生成
const lines = [
"# Agent Skills",
"",
"This file lists installed agent skills.",
"",
"## Installed Skills",
"",
];
for (const skill of installedSkills) {
lines.push(`- [${skill}](.github/skills/${skill}/SKILL.md)`);
}
lines.push("");
lines.push("---");
lines.push("*Auto-generated by Agent Skill Ninja*");
await fs.writeFile(agentsPath, lines.join("\n"), "utf-8");
}