2026-03-19 23:03:23 +00:00
|
|
|
/**
|
|
|
|
|
* Webhook payload transforms for OpenClaw skill deployment.
|
|
|
|
|
*
|
|
|
|
|
* Pure functions — no auth, no network calls, no external dependencies.
|
|
|
|
|
*/
|
2026-03-16 12:06:12 +00:00
|
|
|
|
|
|
|
|
export type Command = 'skill-install';
|
|
|
|
|
|
|
|
|
|
interface SkillEntry {
|
|
|
|
|
skill_id?: string;
|
|
|
|
|
skill_slug?: string;
|
|
|
|
|
skill_name?: string;
|
|
|
|
|
repo_url?: string;
|
|
|
|
|
repo_subpath?: string;
|
|
|
|
|
git_ref?: string;
|
|
|
|
|
commit_sha?: string;
|
2026-03-14 02:35:01 +00:00
|
|
|
}
|
|
|
|
|
|
2026-03-19 23:03:23 +00:00
|
|
|
export function run(command: Command, args: string[]) {
|
2026-03-16 12:06:12 +00:00
|
|
|
if (command === 'skill-install') {
|
|
|
|
|
const payload = args[0] ? JSON.parse(args[0]) : {};
|
|
|
|
|
const result = transformSkillInstall(payload);
|
|
|
|
|
console.log(result.message);
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-19 23:03:23 +00:00
|
|
|
export function transformSkillInstall(payload: Record<string, unknown>) {
|
2026-03-16 12:06:12 +00:00
|
|
|
const body = (payload.payload ?? payload) as Record<string, unknown>;
|
|
|
|
|
const skills = body.skills as SkillEntry[] | undefined;
|
2026-03-14 02:35:01 +00:00
|
|
|
|
2026-03-16 12:06:12 +00:00
|
|
|
if (!skills || skills.length === 0) {
|
|
|
|
|
return {
|
|
|
|
|
message: "skill-update webhook received but no `skills` array in payload. Nothing to install.",
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const lines: string[] = [
|
|
|
|
|
`Install/update ${skills.length} skill(s) from git. Execute all steps directly — do not ask questions.`,
|
|
|
|
|
``,
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
for (const skill of skills) {
|
|
|
|
|
const { repo_url, skill_slug, skill_name, git_ref, repo_subpath } = skill;
|
|
|
|
|
|
|
|
|
|
if (!repo_url) {
|
|
|
|
|
lines.push(`⚠️ Skipping skill "${skill_slug ?? "unknown"}" — missing repo_url.`, ``);
|
|
|
|
|
continue;
|
2026-03-14 02:35:01 +00:00
|
|
|
}
|
|
|
|
|
|
2026-03-16 12:06:12 +00:00
|
|
|
const dirName = skill_slug ?? repo_url.split("/").pop()?.replace(/\.git$/, "") ?? "unknown-skill";
|
|
|
|
|
const installPath = `~/clawd/skills/${dirName}`;
|
|
|
|
|
const subpath = repo_subpath ? `/${repo_subpath}` : "";
|
|
|
|
|
const skillDir = repo_subpath ? `${installPath}/${repo_subpath}` : installPath;
|
|
|
|
|
|
|
|
|
|
lines.push(
|
|
|
|
|
`── Skill: ${skill_name ?? dirName} (${git_ref ?? "default branch"})`,
|
|
|
|
|
` Repo: ${repo_url}`,
|
|
|
|
|
` Target: ${skillDir}`,
|
|
|
|
|
``,
|
|
|
|
|
` Steps:`,
|
|
|
|
|
` 1. If ${installPath} exists: cd ${installPath} && git fetch --tags && git checkout ${git_ref ?? "HEAD"}`,
|
|
|
|
|
` Otherwise: git clone ${repo_url} ${installPath} && cd ${installPath} && git checkout ${git_ref ?? "HEAD"}`,
|
|
|
|
|
` 2. cd ${skillDir}`,
|
|
|
|
|
` 3. If install.sh exists: bash install.sh`,
|
2026-03-19 23:03:23 +00:00
|
|
|
` Otherwise: npm install (if package.json exists) or skip`,
|
2026-03-16 12:06:12 +00:00
|
|
|
` 4. Reply with one line: installed/updated + skill name + version.`,
|
|
|
|
|
``,
|
|
|
|
|
);
|
2026-03-14 02:35:01 +00:00
|
|
|
}
|
|
|
|
|
|
2026-03-16 12:06:12 +00:00
|
|
|
return { message: lines.join("\n") };
|
2026-03-14 02:35:01 +00:00
|
|
|
}
|