Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions shared/scripts/skillpack-build.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,11 @@ function usage() {
" - <out>/vscode/.github/skills/<skill>/SKILL.md",
" - <out>/claude/.claude/skills/<skill>/SKILL.md",
" - <out>/cursor/.cursor/skills/<skill>/SKILL.md",
" - <out>/gemini/.gemini/skills/<skill>/SKILL.md",
" - <out>/antigravity/.agent/skills/<skill>/SKILL.md",
"",
"Options:",
" --targets Comma-separated list of targets (codex, vscode, claude, cursor). Default: codex,vscode,claude,cursor",
" --targets Comma-separated list of targets (codex, vscode, claude, cursor, gemini, antigravity). Default: codex,vscode,claude,cursor,gemini,antigravity",
" --skills Comma-separated list of skill names to build. Default: all skills",
" --clean Remove target directories before building",
"",
Expand All @@ -26,7 +28,7 @@ function usage() {
}

function parseArgs(argv) {
const args = { out: "dist", targets: ["codex", "vscode", "claude", "cursor"], skills: [], clean: false };
const args = { out: "dist", targets: ["codex", "vscode", "claude", "cursor", "gemini", "antigravity"], skills: [], clean: false };
for (const a of argv) {
if (a === "--help" || a === "-h") args.help = true;
else if (a === "--clean") args.clean = true;
Expand Down Expand Up @@ -101,6 +103,8 @@ function buildTarget({ repoRoot, outDir, target, skillDirs }) {
vscode: path.join(outDir, "vscode", ".github", "skills"),
claude: path.join(outDir, "claude", ".claude", "skills"),
cursor: path.join(outDir, "cursor", ".cursor", "skills"),
gemini: path.join(outDir, "gemini", ".gemini", "skills"),
antigravity: path.join(outDir, "antigravity", ".agent", "skills"),
};
const destSkillsRoot = rootByTarget[target];
assert(destSkillsRoot, `Unknown target: ${target}`);
Expand All @@ -117,7 +121,7 @@ function buildTarget({ repoRoot, outDir, target, skillDirs }) {
process.stdout.write(`OK: built ${target} skillpack at ${rel}\n`);
}

const VALID_TARGETS = ["codex", "vscode", "claude", "cursor"];
const VALID_TARGETS = ["codex", "vscode", "claude", "cursor", "gemini", "antigravity"];

function main() {
const args = parseArgs(process.argv.slice(2));
Expand Down
28 changes: 21 additions & 7 deletions shared/scripts/skillpack-install.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ function usage() {
"Options:",
" --dest=<path> Destination repo root (required, unless using --global)",
" --from=<path> Source directory (default: dist)",
" --targets=<list> Comma-separated targets: codex, vscode, claude, claude-global, cursor, cursor-global (default: codex,vscode)",
" --targets=<list> Comma-separated targets: codex, vscode, claude, claude-global, cursor, cursor-global, gemini, gemini-global, antigravity, antigravity-global (default: codex,vscode)",
" --skills=<list> Comma-separated skill names to install (default: all)",
" --mode=<mode> 'replace' (default) or 'merge'",
" --global Shorthand for --targets=claude-global (installs to ~/.claude/skills)",
Expand All @@ -25,6 +25,10 @@ function usage() {
" claude-global Install to ~/.claude/skills/ (user-level, ignores --dest)",
" cursor Install to <dest>/.cursor/skills/",
" cursor-global Install to ~/.cursor/skills/ (user-level, ignores --dest)",
" gemini Install to <dest>/.gemini/skills/",
" gemini-global Install to ~/.gemini/skills/ (user-level, ignores --dest)",
" antigravity Install to <dest>/.agent/skills/",
" antigravity-global Install to ~/.gemini/antigravity/skills/ (user-level, ignores --dest)",
"",
"Examples:",
" # Build and install to a WordPress project",
Expand Down Expand Up @@ -133,18 +137,20 @@ function listSkillDirs(skillsRoot) {
.filter((d) => fs.existsSync(path.join(d, "SKILL.md")));
}

const VALID_TARGETS = ["codex", "vscode", "claude", "claude-global", "cursor", "cursor-global"];
const VALID_TARGETS = ["codex", "vscode", "claude", "claude-global", "cursor", "cursor-global", "gemini", "gemini-global", "antigravity", "antigravity-global"];

// Map target to source subdirectory in dist
function getSourceDir(fromDir, target) {
// claude-global uses the same source as claude; cursor-global uses the same as cursor
const sourceTarget =
target === "claude-global" ? "claude" : target === "cursor-global" ? "cursor" : target;
target === "claude-global" ? "claude" : target === "cursor-global" ? "cursor" : target === "gemini-global" ? "gemini" : target === "antigravity-global" ? "antigravity" : target;
const targetDirMap = {
codex: path.join(fromDir, "codex", ".codex", "skills"),
vscode: path.join(fromDir, "vscode", ".github", "skills"),
claude: path.join(fromDir, "claude", ".claude", "skills"),
cursor: path.join(fromDir, "cursor", ".cursor", "skills"),
gemini: path.join(fromDir, "gemini", ".gemini", "skills"),
antigravity: path.join(fromDir, "antigravity", ".agent", "skills"),
};
return targetDirMap[sourceTarget];
}
Expand All @@ -158,13 +164,21 @@ function getDestDir(destRepoRoot, target) {
if (target === "cursor-global") {
return path.join(os.homedir(), ".cursor", "skills");
}
if (target === "gemini-global") {
return path.join(os.homedir(), ".gemini", "skills");
}
if (target === "antigravity-global") {
return path.join(os.homedir(), ".gemini", "antigravity", "skills");
}

// Other targets require destRepoRoot
const destDirMap = {
codex: path.join(destRepoRoot, ".codex", "skills"),
vscode: path.join(destRepoRoot, ".github", "skills"),
claude: path.join(destRepoRoot, ".claude", "skills"),
cursor: path.join(destRepoRoot, ".cursor", "skills"),
gemini: path.join(destRepoRoot, ".gemini", "skills"),
antigravity: path.join(destRepoRoot, ".agent", "skills"),
};
return destDirMap[target];
}
Expand Down Expand Up @@ -213,14 +227,14 @@ function installTarget({ fromDir, destRepoRoot, target, skillsFilter, mode, dryR
copyDir({ srcDir: srcSkillDir, destDir: destSkillDir });
}

const isGlobal = target === "claude-global" || target === "cursor-global";
const isGlobal = target === "claude-global" || target === "cursor-global" || target === "gemini-global" || target === "antigravity-global";
const location = isGlobal ? destSkillsRoot : path.relative(destRepoRoot, destSkillsRoot) || ".";
process.stdout.write(`OK: installed ${skillDirs.length} skill(s) to ${location}\n`);
}

function listAvailableSkills(fromDir) {
// Check all possible target sources
const sources = ["codex", "vscode", "claude", "cursor"]
const sources = ["codex", "vscode", "claude", "cursor", "gemini", "antigravity"]
.map((t) => getSourceDir(fromDir, t))
.filter((p) => fs.existsSync(p));

Expand Down Expand Up @@ -258,8 +272,8 @@ function main() {
assert(VALID_TARGETS.includes(t), `Invalid target: ${t}. Valid targets: ${VALID_TARGETS.join(", ")}`);
}

// --dest is required unless only using global targets (claude-global, cursor-global)
const needsDest = targets.some((t) => t !== "claude-global" && t !== "cursor-global");
// --dest is required unless only using global targets (claude-global, cursor-global, gemini-global, antigravity-global)
const needsDest = targets.some((t) => t !== "claude-global" && t !== "cursor-global" && t !== "gemini-global" && t !== "antigravity-global");
if (needsDest && !args.dest) {
process.stderr.write("Error: --dest is required for non-global targets.\n\n");
usage();
Expand Down