Merge branch 'main' into add-trae-support

This commit is contained in:
Paul Bakaus
2026-03-21 21:29:42 -07:00
committed by GitHub
246 changed files with 29750 additions and 232 deletions
+23 -16
View File
@@ -205,12 +205,12 @@ function generateApiData(buildDir, skills, patterns) {
id: path.basename(path.dirname(s.filePath)),
name: s.name,
description: s.description,
userInvokable: s.userInvokable,
userInvocable: s.userInvocable,
}));
fs.writeFileSync(path.join(apiDir, 'skills.json'), JSON.stringify(skillsData));
// commands.json (user-invokable skills only)
const commandsData = skillsData.filter(s => s.userInvokable);
// commands.json (user-invocable skills only)
const commandsData = skillsData.filter(s => s.userInvocable);
fs.writeFileSync(path.join(apiDir, 'commands.json'), JSON.stringify(commandsData));
// patterns.json
@@ -342,8 +342,8 @@ async function build() {
// Read source files (unified skills architecture)
const { skills } = readSourceFiles(ROOT_DIR);
const patterns = readPatterns(ROOT_DIR);
const userInvokableCount = skills.filter(s => s.userInvokable).length;
console.log(`📖 Read ${skills.length} skills (${userInvokableCount} user-invokable) and ${patterns.patterns.length + patterns.antipatterns.length} pattern categories\n`);
const userInvocableCount = skills.filter(s => s.userInvocable).length;
console.log(`📖 Read ${skills.length} skills (${userInvocableCount} user-invocable) and ${patterns.patterns.length + patterns.antipatterns.length} pattern categories\n`);
// Transform for each provider
transformCursor(skills, DIST_DIR, patterns);
@@ -380,20 +380,27 @@ async function build() {
copyDistToBuild(DIST_DIR, buildDir);
generateCFConfig(buildDir);
// Copy Claude Code output to project's .claude directory for local development
const claudeCodeSrc = path.join(DIST_DIR, 'claude-code', '.claude');
const claudeCodeDest = path.join(ROOT_DIR, '.claude');
// Copy all provider outputs to project root for local testing
const providers = [
{ dist: 'claude-code', dir: '.claude' },
{ dist: 'cursor', dir: '.cursor' },
{ dist: 'gemini', dir: '.gemini' },
{ dist: 'codex', dir: '.codex' },
{ dist: 'agents', dir: '.agents' },
{ dist: 'kiro', dir: '.kiro' },
{ dist: 'opencode', dir: '.opencode' },
{ dist: 'pi', dir: '.pi' },
];
// Copy skills directory (preserves other files like settings.local.json)
const skillsSrc = path.join(claudeCodeSrc, 'skills');
const skillsDest = path.join(claudeCodeDest, 'skills');
for (const { dist, dir } of providers) {
const skillsSrc = path.join(DIST_DIR, dist, dir, 'skills');
const skillsDest = path.join(ROOT_DIR, dir, 'skills');
// Remove existing and copy fresh
if (fs.existsSync(skillsDest)) fs.rmSync(skillsDest, { recursive: true });
if (fs.existsSync(skillsDest)) fs.rmSync(skillsDest, { recursive: true });
copyDirSync(skillsSrc, skillsDest);
}
copyDirSync(skillsSrc, skillsDest);
console.log(`📋 Synced to .claude/: skills`);
console.log(`📋 Synced skills to: ${providers.map(p => p.dir).join(', ')}`);
console.log('\n✨ Build complete!');
}
+8 -8
View File
@@ -5,9 +5,9 @@ import { cleanDir, ensureDir, writeFile, generateYamlFrontmatter, replacePlaceho
* Agents Transformer (VS Code Copilot + Antigravity)
*
* All skills output to .agents/skills/{name}/SKILL.md
* Frontmatter: name, description, user-invokable (if true), argument-hint (from args)
* Frontmatter: name, description, user-invocable (if true), argument-hint (from args)
*
* @param {Array} skills - All skills (including user-invokable ones)
* @param {Array} skills - All skills (including user-invocable ones)
* @param {string} distDir - Distribution output directory
* @param {Object} patterns - Design patterns data (unused)
* @param {Object} options - Optional settings
@@ -21,7 +21,7 @@ export function transformAgents(skills, distDir, patterns = null, options = {})
ensureDir(skillsDir);
const allSkillNames = skills.map(s => s.name);
const commandNames = skills.filter(s => s.userInvokable).map(s => `${prefix}${s.name}`);
const commandNames = skills.filter(s => s.userInvocable).map(s => `${prefix}${s.name}`);
let refCount = 0;
for (const skill of skills) {
const skillName = `${prefix}${skill.name}`;
@@ -32,10 +32,10 @@ export function transformAgents(skills, distDir, patterns = null, options = {})
description: skill.description,
};
if (skill.userInvokable) frontmatterObj['user-invokable'] = true;
if (skill.userInvocable) frontmatterObj['user-invocable'] = true;
// Build argument-hint from args array for user-invokable skills
if (skill.userInvokable && skill.args && skill.args.length > 0) {
// Build argument-hint from args array for user-invocable skills
if (skill.userInvocable && skill.args && skill.args.length > 0) {
const hints = skill.args.map(arg => {
return arg.required ? `<${arg.name}>` : `[${arg.name.toUpperCase()}=<value>]`;
});
@@ -62,8 +62,8 @@ export function transformAgents(skills, distDir, patterns = null, options = {})
}
}
const userInvokableCount = skills.filter(s => s.userInvokable).length;
const userInvocableCount = skills.filter(s => s.userInvocable).length;
const refInfo = refCount > 0 ? ` (${refCount} reference files)` : '';
const prefixInfo = prefix ? ` [${prefix}prefixed]` : '';
console.log(`✓ Agents${prefixInfo}: ${skills.length} skills (${userInvokableCount} user-invokable)${refInfo}`);
console.log(`✓ Agents${prefixInfo}: ${skills.length} skills (${userInvocableCount} user-invocable)${refInfo}`);
}
+6 -6
View File
@@ -7,11 +7,11 @@ import { cleanDir, ensureDir, writeFile, generateYamlFrontmatter, replacePlaceho
* All skills output to .claude/skills/{name}/SKILL.md
* User-invokable skills get args support in frontmatter.
*
* @param {Array} skills - All skills (including user-invokable ones)
* @param {Array} skills - All skills (including user-invocable ones)
* @param {string} distDir - Distribution output directory
* @param {Object} patterns - Design patterns data (unused, kept for interface consistency)
* @param {Object} options - Optional settings
* @param {string} options.prefix - Prefix to add to user-invokable skill names (e.g., 'i-')
* @param {string} options.prefix - Prefix to add to user-invocable skill names (e.g., 'i-')
* @param {string} options.outputSuffix - Suffix for output directory (e.g., '-prefixed')
*/
export function transformClaudeCode(skills, distDir, patterns = null, options = {}) {
@@ -23,7 +23,7 @@ export function transformClaudeCode(skills, distDir, patterns = null, options =
ensureDir(skillsDir);
const allSkillNames = skills.map(s => s.name);
const commandNames = skills.filter(s => s.userInvokable).map(s => `${prefix}${s.name}`);
const commandNames = skills.filter(s => s.userInvocable).map(s => `${prefix}${s.name}`);
let refCount = 0;
for (const skill of skills) {
const skillName = `${prefix}${skill.name}`;
@@ -34,7 +34,7 @@ export function transformClaudeCode(skills, distDir, patterns = null, options =
description: skill.description,
};
if (skill.userInvokable) frontmatterObj['user-invokable'] = true;
if (skill.userInvocable) frontmatterObj['user-invocable'] = true;
if (skill.args && skill.args.length > 0) frontmatterObj.args = skill.args;
if (skill.license) frontmatterObj.license = skill.license;
if (skill.compatibility) frontmatterObj.compatibility = skill.compatibility;
@@ -61,8 +61,8 @@ export function transformClaudeCode(skills, distDir, patterns = null, options =
}
}
const userInvokableCount = skills.filter(s => s.userInvokable).length;
const userInvocableCount = skills.filter(s => s.userInvocable).length;
const refInfo = refCount > 0 ? ` (${refCount} reference files)` : '';
const prefixInfo = prefix ? ` [${prefix}prefixed]` : '';
console.log(`✓ Claude Code${prefixInfo}: ${skills.length} skills (${userInvokableCount} user-invokable)${refInfo}`);
console.log(`✓ Claude Code${prefixInfo}: ${skills.length} skills (${userInvocableCount} user-invocable)${refInfo}`);
}
+11 -11
View File
@@ -5,14 +5,14 @@ import { cleanDir, ensureDir, writeFile, generateYamlFrontmatter, replacePlaceho
* Codex Transformer (Skills Only)
*
* All skills output to .codex/skills/{name}/SKILL.md
* Frontmatter: name, description, argument-hint (from args for user-invokable)
* For user-invokable skills: {{argname}} becomes $ARGNAME in body
* Frontmatter: name, description, argument-hint (from args for user-invocable)
* For user-invocable skills: {{argname}} becomes $ARGNAME in body
*
* @param {Array} skills - All skills (including user-invokable ones)
* @param {Array} skills - All skills (including user-invocable ones)
* @param {string} distDir - Distribution output directory
* @param {Object} patterns - Design patterns data (unused)
* @param {Object} options - Optional settings
* @param {string} options.prefix - Prefix to add to user-invokable skill names (e.g., 'i-')
* @param {string} options.prefix - Prefix to add to user-invocable skill names (e.g., 'i-')
* @param {string} options.outputSuffix - Suffix for output directory (e.g., '-prefixed')
*/
export function transformCodex(skills, distDir, patterns = null, options = {}) {
@@ -24,7 +24,7 @@ export function transformCodex(skills, distDir, patterns = null, options = {}) {
ensureDir(skillsDir);
const allSkillNames = skills.map(s => s.name);
const commandNames = skills.filter(s => s.userInvokable).map(s => `${prefix}${s.name}`);
const commandNames = skills.filter(s => s.userInvocable).map(s => `${prefix}${s.name}`);
let refCount = 0;
for (const skill of skills) {
const skillName = `${prefix}${skill.name}`;
@@ -35,8 +35,8 @@ export function transformCodex(skills, distDir, patterns = null, options = {}) {
description: skill.description,
};
// Build argument-hint from args array for user-invokable skills
if (skill.userInvokable && skill.args && skill.args.length > 0) {
// Build argument-hint from args array for user-invocable skills
if (skill.userInvocable && skill.args && skill.args.length > 0) {
const hints = skill.args.map(arg => {
return arg.required ? `<${arg.name}>` : `[${arg.name.toUpperCase()}=<value>]`;
});
@@ -48,8 +48,8 @@ export function transformCodex(skills, distDir, patterns = null, options = {}) {
let skillBody = replacePlaceholders(skill.body, 'codex', commandNames);
if (prefix) skillBody = prefixSkillReferences(skillBody, prefix, allSkillNames);
// For user-invokable skills, transform remaining {{argname}} to $ARGNAME
if (skill.userInvokable) {
// For user-invocable skills, transform remaining {{argname}} to $ARGNAME
if (skill.userInvocable) {
skillBody = skillBody.replace(/\{\{([^}]+)\}\}/g, (match, argName) => {
return `$${argName.toUpperCase()}`;
});
@@ -72,8 +72,8 @@ export function transformCodex(skills, distDir, patterns = null, options = {}) {
}
}
const userInvokableCount = skills.filter(s => s.userInvokable).length;
const userInvocableCount = skills.filter(s => s.userInvocable).length;
const refInfo = refCount > 0 ? ` (${refCount} reference files)` : '';
const prefixInfo = prefix ? ` [${prefix}prefixed]` : '';
console.log(`✓ Codex${prefixInfo}: ${skills.length} skills (${userInvokableCount} user-invokable)${refInfo}`);
console.log(`✓ Codex${prefixInfo}: ${skills.length} skills (${userInvocableCount} user-invocable)${refInfo}`);
}
+5 -5
View File
@@ -7,11 +7,11 @@ import { cleanDir, ensureDir, writeFile, generateYamlFrontmatter, replacePlaceho
* All skills output to .cursor/skills/{name}/SKILL.md
* Frontmatter: name, description, license
*
* @param {Array} skills - All skills (including user-invokable ones)
* @param {Array} skills - All skills (including user-invocable ones)
* @param {string} distDir - Distribution output directory
* @param {Object} patterns - Design patterns data (unused)
* @param {Object} options - Optional settings
* @param {string} options.prefix - Prefix to add to user-invokable skill names (e.g., 'i-')
* @param {string} options.prefix - Prefix to add to user-invocable skill names (e.g., 'i-')
* @param {string} options.outputSuffix - Suffix for output directory (e.g., '-prefixed')
*/
export function transformCursor(skills, distDir, patterns = null, options = {}) {
@@ -23,7 +23,7 @@ export function transformCursor(skills, distDir, patterns = null, options = {})
ensureDir(skillsDir);
const allSkillNames = skills.map(s => s.name);
const commandNames = skills.filter(s => s.userInvokable).map(s => `${prefix}${s.name}`);
const commandNames = skills.filter(s => s.userInvocable).map(s => `${prefix}${s.name}`);
let refCount = 0;
for (const skill of skills) {
const skillName = `${prefix}${skill.name}`;
@@ -55,8 +55,8 @@ export function transformCursor(skills, distDir, patterns = null, options = {})
}
}
const userInvokableCount = skills.filter(s => s.userInvokable).length;
const userInvocableCount = skills.filter(s => s.userInvocable).length;
const refInfo = refCount > 0 ? ` (${refCount} reference files)` : '';
const prefixInfo = prefix ? ` [${prefix}prefixed]` : '';
console.log(`✓ Cursor${prefixInfo}: ${skills.length} skills (${userInvokableCount} user-invokable)${refInfo}`);
console.log(`✓ Cursor${prefixInfo}: ${skills.length} skills (${userInvocableCount} user-invocable)${refInfo}`);
}
+8 -8
View File
@@ -6,13 +6,13 @@ import { cleanDir, ensureDir, writeFile, generateYamlFrontmatter, replacePlaceho
*
* All skills output to .gemini/skills/{name}/SKILL.md
* Frontmatter: name, description
* For user-invokable skills: {{arg}} placeholders become {{args}} in body
* For user-invocable skills: {{arg}} placeholders become {{args}} in body
*
* @param {Array} skills - All skills (including user-invokable ones)
* @param {Array} skills - All skills (including user-invocable ones)
* @param {string} distDir - Distribution output directory
* @param {Object} patterns - Design patterns data (unused)
* @param {Object} options - Optional settings
* @param {string} options.prefix - Prefix to add to user-invokable skill names (e.g., 'i-')
* @param {string} options.prefix - Prefix to add to user-invocable skill names (e.g., 'i-')
* @param {string} options.outputSuffix - Suffix for output directory (e.g., '-prefixed')
*/
export function transformGemini(skills, distDir, patterns = null, options = {}) {
@@ -24,7 +24,7 @@ export function transformGemini(skills, distDir, patterns = null, options = {})
ensureDir(skillsDir);
const allSkillNames = skills.map(s => s.name);
const commandNames = skills.filter(s => s.userInvokable).map(s => `${prefix}${s.name}`);
const commandNames = skills.filter(s => s.userInvocable).map(s => `${prefix}${s.name}`);
let refCount = 0;
for (const skill of skills) {
const skillName = `${prefix}${skill.name}`;
@@ -37,8 +37,8 @@ export function transformGemini(skills, distDir, patterns = null, options = {})
let skillBody = replacePlaceholders(skill.body, 'gemini', commandNames);
if (prefix) skillBody = prefixSkillReferences(skillBody, prefix, allSkillNames);
// For user-invokable skills, replace remaining {{arg}} placeholders with {{args}}
if (skill.userInvokable) {
// For user-invocable skills, replace remaining {{arg}} placeholders with {{args}}
if (skill.userInvocable) {
skillBody = skillBody.replace(/\{\{[^}]+\}\}/g, '{{args}}');
}
@@ -59,8 +59,8 @@ export function transformGemini(skills, distDir, patterns = null, options = {})
}
}
const userInvokableCount = skills.filter(s => s.userInvokable).length;
const userInvocableCount = skills.filter(s => s.userInvocable).length;
const refInfo = refCount > 0 ? ` (${refCount} reference files)` : '';
const prefixInfo = prefix ? ` [${prefix}prefixed]` : '';
console.log(`✓ Gemini${prefixInfo}: ${skills.length} skills (${userInvokableCount} user-invokable)${refInfo}`);
console.log(`✓ Gemini${prefixInfo}: ${skills.length} skills (${userInvocableCount} user-invocable)${refInfo}`);
}
+4 -4
View File
@@ -7,7 +7,7 @@ import { cleanDir, ensureDir, writeFile, generateYamlFrontmatter, replacePlaceho
* All skills output to .kiro/skills/{name}/SKILL.md
* Frontmatter: name, description, license, compatibility, metadata
*
* @param {Array} skills - All skills (including user-invokable ones)
* @param {Array} skills - All skills (including user-invocable ones)
* @param {string} distDir - Distribution output directory
* @param {Object} patterns - Design patterns data (unused)
* @param {Object} options - Optional settings
@@ -23,7 +23,7 @@ export function transformKiro(skills, distDir, patterns = null, options = {}) {
ensureDir(skillsDir);
const allSkillNames = skills.map(s => s.name);
const commandNames = skills.filter(s => s.userInvokable).map(s => `${prefix}${s.name}`);
const commandNames = skills.filter(s => s.userInvocable).map(s => `${prefix}${s.name}`);
let refCount = 0;
for (const skill of skills) {
const skillName = `${prefix}${skill.name}`;
@@ -58,8 +58,8 @@ export function transformKiro(skills, distDir, patterns = null, options = {}) {
}
}
const userInvokableCount = skills.filter(s => s.userInvokable).length;
const userInvocableCount = skills.filter(s => s.userInvocable).length;
const refInfo = refCount > 0 ? ` (${refCount} reference files)` : '';
const prefixInfo = prefix ? ` [${prefix}prefixed]` : '';
console.log(`✓ Kiro${prefixInfo}: ${skills.length} skills (${userInvokableCount} user-invokable)${refInfo}`);
console.log(`✓ Kiro${prefixInfo}: ${skills.length} skills (${userInvocableCount} user-invocable)${refInfo}`);
}
+6 -6
View File
@@ -14,11 +14,11 @@ import {
* All skills output to .opencode/skills/{name}/SKILL.md
* User-invokable skills get args support in frontmatter.
*
* @param {Array} skills - All skills (including user-invokable ones)
* @param {Array} skills - All skills (including user-invocable ones)
* @param {string} distDir - Distribution output directory
* @param {Object} patterns - Design patterns data (unused, kept for interface consistency)
* @param {Object} options - Optional settings
* @param {string} options.prefix - Prefix to add to user-invokable skill names (e.g., 'i-')
* @param {string} options.prefix - Prefix to add to user-invocable skill names (e.g., 'i-')
* @param {string} options.outputSuffix - Suffix for output directory (e.g., '-prefixed')
*/
export function transformOpenCode(
@@ -36,7 +36,7 @@ export function transformOpenCode(
const allSkillNames = skills.map((s) => s.name);
const commandNames = skills
.filter((s) => s.userInvokable)
.filter((s) => s.userInvocable)
.map((s) => `${prefix}${s.name}`);
let refCount = 0;
for (const skill of skills) {
@@ -48,7 +48,7 @@ export function transformOpenCode(
description: skill.description,
};
if (skill.userInvokable) frontmatterObj['user-invokable'] = true;
if (skill.userInvocable) frontmatterObj['user-invocable'] = true;
if (skill.args && skill.args.length > 0) frontmatterObj.args = skill.args;
if (skill.license) frontmatterObj.license = skill.license;
if (skill.compatibility) frontmatterObj.compatibility = skill.compatibility;
@@ -77,8 +77,8 @@ export function transformOpenCode(
}
}
const userInvokableCount = skills.filter((s) => s.userInvokable).length;
const userInvocableCount = skills.filter((s) => s.userInvocable).length;
const refInfo = refCount > 0 ? ` (${refCount} reference files)` : '';
const prefixInfo = prefix ? ` [${prefix}prefixed]` : '';
console.log(`✓ OpenCode${prefixInfo}: ${skills.length} skills (${userInvokableCount} user-invokable)${refInfo}`);
console.log(`✓ OpenCode${prefixInfo}: ${skills.length} skills (${userInvocableCount} user-invocable)${refInfo}`);
}
+4 -4
View File
@@ -7,7 +7,7 @@ import { cleanDir, ensureDir, writeFile, generateYamlFrontmatter, replacePlaceho
* All skills output to .pi/skills/{name}/SKILL.md
* Frontmatter: name, description, license, compatibility, metadata
*
* @param {Array} skills - All skills (including user-invokable ones)
* @param {Array} skills - All skills (including user-invocable ones)
* @param {string} distDir - Distribution output directory
* @param {Object} patterns - Design patterns data (unused)
* @param {Object} options - Optional settings
@@ -23,7 +23,7 @@ export function transformPi(skills, distDir, patterns = null, options = {}) {
ensureDir(skillsDir);
const allSkillNames = skills.map(s => s.name);
const commandNames = skills.filter(s => s.userInvokable).map(s => `${prefix}${s.name}`);
const commandNames = skills.filter(s => s.userInvocable).map(s => `${prefix}${s.name}`);
let refCount = 0;
for (const skill of skills) {
const skillName = `${prefix}${skill.name}`;
@@ -58,8 +58,8 @@ export function transformPi(skills, distDir, patterns = null, options = {}) {
}
}
const userInvokableCount = skills.filter(s => s.userInvokable).length;
const userInvocableCount = skills.filter(s => s.userInvocable).length;
const refInfo = refCount > 0 ? ` (${refCount} reference files)` : '';
const prefixInfo = prefix ? ` [${prefix}prefixed]` : '';
console.log(`✓ Pi${prefixInfo}: ${skills.length} skills (${userInvokableCount} user-invokable)${refInfo}`);
console.log(`✓ Pi${prefixInfo}: ${skills.length} skills (${userInvocableCount} user-invocable)${refInfo}`);
}
+6 -3
View File
@@ -104,7 +104,7 @@ export function readFilesRecursive(dir, fileList = []) {
/**
* Read and parse all source files (unified skills architecture)
* All source lives in source/skills/{name}/SKILL.md
* Returns { skills } where each skill has userInvokable flag
* Returns { skills } where each skill has userInvocable flag
*/
export function readSourceFiles(rootDir) {
const skillsDir = path.join(rootDir, 'source/skills');
@@ -147,7 +147,7 @@ export function readSourceFiles(rootDir) {
compatibility: frontmatter.compatibility || '',
metadata: frontmatter.metadata || null,
allowedTools: frontmatter['allowed-tools'] || '',
userInvokable: frontmatter['user-invokable'] === true || frontmatter['user-invokable'] === 'true',
userInvocable: frontmatter['user-invocable'] === true || frontmatter['user-invocable'] === 'true',
args: frontmatter.args || [],
context: frontmatter.context || null,
body,
@@ -331,7 +331,10 @@ export function prefixSkillReferences(content, prefix, skillNames) {
result = result.replace(new RegExp(`\\/(?=${escapeRegex(name)}(?:[^a-zA-Z0-9_-]|$))`, 'g'), `/${prefix}`);
// Replace `the skillname skill` references
result = result.replace(new RegExp(`the ${escapeRegex(name)} skill`, 'gi'), `the ${prefixed} skill`);
result = result.replace(
new RegExp(`(the) ${escapeRegex(name)} skill`, 'gi'),
(_, article) => `${article} ${prefixed} skill`
);
}
return result;