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
6 changes: 4 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ jobs:
- name: Run local eval harness
run: node eval/harness/run.mjs

- name: Build skillpacks (Codex + VS Code)
run: node shared/scripts/skillpack-build.mjs --clean --out=dist --targets=codex,vscode
- name: Build skillpacks (Codex + VS Code + Junie)
run: node shared/scripts/skillpack-build.mjs --clean --out=dist --targets=codex,vscode,junie

- name: Install skillpacks (smoke)
run: |
Expand All @@ -28,6 +28,8 @@ jobs:
node shared/scripts/skillpack-install.mjs --from=dist --dest=/tmp/skillpack-install-test --targets=codex,vscode
test -f /tmp/skillpack-install-test/.codex/skills/wordpress-router/SKILL.md
test -f /tmp/skillpack-install-test/.github/skills/wordpress-router/SKILL.md
# verify Junie guidelines file existed in build output
test -f dist/junie/.junie/wordpress_guidelines.md

- uses: actions/setup-python@v5
with:
Expand Down
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,14 +66,15 @@ cd agent-skills
node shared/scripts/skillpack-build.mjs --clean

# Install into your WordPress project
node shared/scripts/skillpack-install.mjs --dest=../your-wp-project --targets=codex,vscode,claude,cursor
node shared/scripts/skillpack-install.mjs --dest=../your-wp-project --targets=codex,vscode,claude,cursor,junie
```

This copies skills into:
- `.codex/skills/` for OpenAI Codex
- `.github/skills/` for VS Code / GitHub Copilot
- `.claude/skills/` for Claude Code (project-level)
- `.cursor/skills/` for Cursor (project-level)
- `.junie/skills/` for Junie (project-level) plus an included `wordpress_guidelines.md`

### Install globally for Cursor

Expand Down
4 changes: 3 additions & 1 deletion docs/packaging.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,15 @@ Outputs:
- `dist/vscode/.github/skills/*` (VS Code / Copilot repo layout)
- `dist/claude/.claude/skills/*` (Claude Code repo layout)
- `dist/cursor/.cursor/skills/*` (Cursor repo layout)
- `dist/junie/.junie/skills/*` (Junie target layout)
- `dist/junie/.junie/wordpress_guidelines.md` (additional guidelines file)

## Install into another repo

1. Build dist (above).
2. Install into a destination repo:

- `node shared/scripts/skillpack-install.mjs --dest=../some-repo --targets=codex,vscode,claude,cursor`
- `node shared/scripts/skillpack-install.mjs --dest=../some-repo --targets=codex,vscode,claude,cursor,junie`

By default, install mode is `replace` (it replaces only the skill directories it installs).

8 changes: 4 additions & 4 deletions eval/scenarios/skillpack-build-and-install.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
{
"name": "Build and install skillpacks",
"skills": [],
"query": "Package this repo's skills for Codex, VS Code, Claude, and Cursor and install them into another repository.",
"query": "Package this repo's skills for Codex, VS Code, Claude, Cursor, and Junie and install them into another repository.",
"expected_behavior": [
"Step 1: Run build command: node shared/scripts/skillpack-build.mjs --clean --targets=codex,vscode,claude,cursor",
"Step 2: Verify build output in dist/ directory",
"Step 1: Run build command: node shared/scripts/skillpack-build.mjs --clean --targets=codex,vscode,claude,cursor,junie",
"Step 2: Verify build output in dist/ directory (including dist/junie/.junie/wordpress_guidelines.md)",
"Step 3: Run install command: node shared/scripts/skillpack-install.mjs --from=dist --dest=<repo-root> --targets=codex,vscode,claude,cursor",
"Step 4: Verify skills installed in target repository",
"Step 5: Confirm no symlinks in installed skills (files are copied)"
Expand All @@ -14,6 +14,6 @@
"Output created in dist/ directory",
"Install command copies to target repository",
"No symlinks in installed skills",
"Codex, vscode, claude, and cursor targets supported"
"Codex, vscode, claude, cursor, and junie targets supported"
]
}
44 changes: 38 additions & 6 deletions shared/scripts/skillpack-build.mjs
Original file line number Diff line number Diff line change
@@ -1,32 +1,37 @@
import fs from "node:fs";
import path from "node:path";
import http from "node:http";
import https from "node:https";

function usage() {
process.stderr.write(
[
"Usage:",
" node shared/scripts/skillpack-build.mjs [--out=dist] [--targets=codex,vscode,claude,cursor] [--skills=skill1,skill2] [--clean]",
" node shared/scripts/skillpack-build.mjs [--out=dist] [--targets=codex,vscode,claude,cursor,junie] [--skills=skill1,skill2] [--clean]",
"",
"Outputs:",
" - <out>/codex/.codex/skills/<skill>/SKILL.md",
" - <out>/vscode/.github/skills/<skill>/SKILL.md",
" - <out>/claude/.claude/skills/<skill>/SKILL.md",
" - <out>/cursor/.cursor/skills/<skill>/SKILL.md",
" - <out>/junie/.junie/skills/<skill>/SKILL.md",
" - <out>/junie/.junie/wordpress_guidelines.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, junie). Default: codex,vscode,claude,cursor,junie",
" --skills Comma-separated list of skill names to build. Default: all skills",
" --clean Remove target directories before building",
"",
"Notes:",
"- Avoids symlinks (Codex ignores symlinked directories).",
""," - junie target also downloads WordPress guidelines into the .junie folder.",
"",
].join("\n")
);
}

function parseArgs(argv) {
const args = { out: "dist", targets: ["codex", "vscode", "claude", "cursor"], skills: [], clean: false };
const args = { out: "dist", targets: ["codex", "vscode", "claude", "cursor", "junie"], 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 +106,7 @@ 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"),
junie: path.join(outDir, "junie", ".junie", "skills"),
};
const destSkillsRoot = rootByTarget[target];
assert(destSkillsRoot, `Unknown target: ${target}`);
Expand All @@ -117,9 +123,22 @@ 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", "junie"];

function main() {
async function downloadGuidelines(destRoot) {
// Download the WordPress guidelines markdown and save it into destRoot
const url = "https://github.com/user-attachments/files/25775597/wordpress_guidelines.md";
const destPath = path.join(destRoot, "wordpress_guidelines.md");

const res = await fetch(url);
if (!res.ok) {
throw new Error(`Failed to download guidelines: ${res.status} ${res.statusText}`);
}
const content = await res.text();
fs.writeFileSync(destPath, content);
}

async function main() {
const args = parseArgs(process.argv.slice(2));
if (args.help) {
usage();
Expand Down Expand Up @@ -160,8 +179,21 @@ function main() {

for (const target of targets) {
buildTarget({ repoRoot, outDir, target, skillDirs });
if (target === "junie") {
// ensure guidelines file is present in the root of the .junie folder
const junieRoot = path.join(outDir, "junie", ".junie");
try {
await downloadGuidelines(junieRoot);
process.stdout.write(`OK: downloaded guidelines to ${path.relative(repoRoot, junieRoot)}\n`);
} catch (err) {
process.stderr.write(`Warning: could not download guidelines: ${err.message}\n`);
}
}
}
}

main();
main().catch((err) => {
console.error(err);
process.exit(1);
});