Add prefixed command option to avoid conflicts

Users can now toggle "Prefix commands with /i-" in the download section
to get bundles with all commands prefixed (e.g., /i-audit instead of /audit).
This helps avoid conflicts with existing custom commands.

Build system changes:
- Transformers now accept optional prefix/outputSuffix parameters
- Build generates both unprefixed and i-prefixed variants
- ZIP bundles created for both variants

UI changes:
- Add toggle switch to download section
- Toggle controls which bundle variant gets downloaded
- Styled to match existing design language

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Paul Bakaus
2026-01-07 20:06:36 -08:00
co-authored by Claude Opus 4.5
parent 8a4e4bd380
commit 3083f8addc
103 changed files with 14852 additions and 24 deletions
+10 -3
View File
@@ -138,13 +138,20 @@ async function build() {
const patterns = readPatterns(ROOT_DIR);
console.log(`📖 Read ${commands.length} commands, ${skills.length} skills, and ${patterns.patterns.length + patterns.antipatterns.length} pattern categories\n`);
// Transform for each provider
// Transform for each provider (unprefixed)
transformCursor(commands, skills, DIST_DIR, patterns);
transformClaudeCode(commands, skills, DIST_DIR, patterns);
transformGemini(commands, skills, DIST_DIR, patterns);
transformCodex(commands, skills, DIST_DIR, patterns);
// Create ZIP bundles
// Transform for each provider (prefixed with i-)
const prefixOptions = { prefix: 'i-', outputSuffix: '-prefixed' };
transformCursor(commands, skills, DIST_DIR, patterns, prefixOptions);
transformClaudeCode(commands, skills, DIST_DIR, patterns, prefixOptions);
transformGemini(commands, skills, DIST_DIR, patterns, prefixOptions);
transformCodex(commands, skills, DIST_DIR, patterns, prefixOptions);
// Create ZIP bundles (both unprefixed and prefixed)
await createAllZips(DIST_DIR);
// Copy Claude Code output to project's .claude directory for local development
+12 -5
View File
@@ -51,9 +51,14 @@ These anti-patterns are baked into training data from countless generic template
* Keeps full YAML frontmatter with args support.
* Skills stored in subdirectories with SKILL.md filename.
* Supports reference files in skill subdirectories.
*
* @param {Object} options - Optional settings
* @param {string} options.prefix - Prefix to add to command names (e.g., 'i-')
* @param {string} options.outputSuffix - Suffix for output directory (e.g., '-prefixed')
*/
export function transformClaudeCode(commands, skills, distDir, patterns = null) {
const claudeDir = path.join(distDir, 'claude-code');
export function transformClaudeCode(commands, skills, distDir, patterns = null, options = {}) {
const { prefix = '', outputSuffix = '' } = options;
const claudeDir = path.join(distDir, `claude-code${outputSuffix}`);
const commandsDir = path.join(claudeDir, '.claude/commands');
const skillsDir = path.join(claudeDir, '.claude/skills');
@@ -63,8 +68,9 @@ export function transformClaudeCode(commands, skills, distDir, patterns = null)
// Commands: Keep frontmatter + body
for (const command of commands) {
const commandName = `${prefix}${command.name}`;
const frontmatter = generateYamlFrontmatter({
name: command.name,
name: commandName,
description: command.description,
...(command.context && { context: command.context }),
...(command.args.length > 0 && { args: command.args })
@@ -72,7 +78,7 @@ export function transformClaudeCode(commands, skills, distDir, patterns = null)
const commandBody = replacePlaceholders(command.body, 'claude-code');
const content = `${frontmatter}\n\n${commandBody}`;
const outputPath = path.join(commandsDir, `${command.name}.md`);
const outputPath = path.join(commandsDir, `${commandName}.md`);
writeFile(outputPath, content);
}
@@ -113,6 +119,7 @@ export function transformClaudeCode(commands, skills, distDir, patterns = null)
}
const refInfo = refCount > 0 ? ` (${refCount} reference files)` : '';
console.log(`✓ Claude Code: ${commands.length} commands, ${skills.length} skills${refInfo}`);
const prefixInfo = prefix ? ` [${prefix}prefixed]` : '';
console.log(`✓ Claude Code${prefixInfo}: ${commands.length} commands, ${skills.length} skills${refInfo}`);
}
+11 -4
View File
@@ -51,9 +51,14 @@ These anti-patterns are baked into training data from countless generic template
* Commands: Uses argument-hint format with $VARIABLE placeholders in .codex/prompts/
* Skills: Uses Agent Skills standard with SKILL.md in .codex/skills/{name}/
* Reference files are copied to skill subdirectories
*
* @param {Object} options - Optional settings
* @param {string} options.prefix - Prefix to add to command names (e.g., 'i-')
* @param {string} options.outputSuffix - Suffix for output directory (e.g., '-prefixed')
*/
export function transformCodex(commands, skills, distDir, patterns = null) {
const codexDir = path.join(distDir, 'codex');
export function transformCodex(commands, skills, distDir, patterns = null, options = {}) {
const { prefix = '', outputSuffix = '' } = options;
const codexDir = path.join(distDir, `codex${outputSuffix}`);
const promptsDir = path.join(codexDir, '.codex/prompts');
const skillsDir = path.join(codexDir, '.codex/skills');
@@ -63,6 +68,7 @@ export function transformCodex(commands, skills, distDir, patterns = null) {
// Commands: Transform to Codex prompt format
for (const command of commands) {
const commandName = `${prefix}${command.name}`;
const yamlLines = ['---'];
yamlLines.push(`description: ${command.description}`);
@@ -84,7 +90,7 @@ export function transformCodex(commands, skills, distDir, patterns = null) {
});
const content = `${yamlLines.join('\n')}\n\n${body}`;
const outputPath = path.join(promptsDir, `${command.name}.md`);
const outputPath = path.join(promptsDir, `${commandName}.md`);
writeFile(outputPath, content);
}
@@ -118,5 +124,6 @@ export function transformCodex(commands, skills, distDir, patterns = null) {
}
const refInfo = refCount > 0 ? ` (${refCount} reference files)` : '';
console.log(`✓ Codex: ${commands.length} prompts, ${skills.length} skills${refInfo}`);
const prefixInfo = prefix ? ` [${prefix}prefixed]` : '';
console.log(`✓ Codex${prefixInfo}: ${commands.length} prompts, ${skills.length} skills${refInfo}`);
}
+11 -4
View File
@@ -53,9 +53,14 @@ These anti-patterns are baked into training data from countless generic template
* Reference files are copied to skill subdirectories
*
* Note: Agent Skills in Cursor require nightly channel and are agent-decided rules.
*
* @param {Object} options - Optional settings
* @param {string} options.prefix - Prefix to add to command names (e.g., 'i-')
* @param {string} options.outputSuffix - Suffix for output directory (e.g., '-prefixed')
*/
export function transformCursor(commands, skills, distDir, patterns = null) {
const cursorDir = path.join(distDir, 'cursor');
export function transformCursor(commands, skills, distDir, patterns = null, options = {}) {
const { prefix = '', outputSuffix = '' } = options;
const cursorDir = path.join(distDir, `cursor${outputSuffix}`);
const commandsDir = path.join(cursorDir, '.cursor/commands');
const skillsDir = path.join(cursorDir, '.cursor/skills');
@@ -65,8 +70,9 @@ export function transformCursor(commands, skills, distDir, patterns = null) {
// Commands: Body only (Cursor doesn't support command frontmatter/args)
for (const command of commands) {
const commandName = `${prefix}${command.name}`;
const commandBody = replacePlaceholders(command.body, 'cursor');
const outputPath = path.join(commandsDir, `${command.name}.md`);
const outputPath = path.join(commandsDir, `${commandName}.md`);
writeFile(outputPath, commandBody);
}
@@ -100,5 +106,6 @@ export function transformCursor(commands, skills, distDir, patterns = null) {
}
const refInfo = refCount > 0 ? ` (${refCount} reference files)` : '';
console.log(`✓ Cursor: ${commands.length} commands, ${skills.length} skills${refInfo}`);
const prefixInfo = prefix ? ` [${prefix}prefixed]` : '';
console.log(`✓ Cursor${prefixInfo}: ${commands.length} commands, ${skills.length} skills${refInfo}`);
}
+11 -4
View File
@@ -7,9 +7,14 @@ import { cleanDir, ensureDir, writeFile, replacePlaceholders } from '../utils.js
* Commands: Converts to TOML format with {{args}} placeholders
* Skills: Creates modular files imported via @./GEMINI.{name}.md syntax
* Reference files are inlined into the main skill file for Gemini
*
* @param {Object} options - Optional settings
* @param {string} options.prefix - Prefix to add to command names (e.g., 'i-')
* @param {string} options.outputSuffix - Suffix for output directory (e.g., '-prefixed')
*/
export function transformGemini(commands, skills, distDir, patterns = null) {
const geminiDir = path.join(distDir, 'gemini');
export function transformGemini(commands, skills, distDir, patterns = null, options = {}) {
const { prefix = '', outputSuffix = '' } = options;
const geminiDir = path.join(distDir, `gemini${outputSuffix}`);
const commandsDir = path.join(geminiDir, '.gemini/commands');
cleanDir(geminiDir);
@@ -17,6 +22,7 @@ export function transformGemini(commands, skills, distDir, patterns = null) {
// Commands: Transform to TOML
for (const command of commands) {
const commandName = `${prefix}${command.name}`;
// First replace our placeholders, then replace remaining {{arg}} with {{args}}
let prompt = replacePlaceholders(command.body, 'gemini');
prompt = prompt.replace(/\{\{[^}]+\}\}/g, '{{args}}');
@@ -28,7 +34,7 @@ export function transformGemini(commands, skills, distDir, patterns = null) {
`"""`
].join('\n');
const outputPath = path.join(commandsDir, `${command.name}.toml`);
const outputPath = path.join(commandsDir, `${commandName}.toml`);
writeFile(outputPath, toml);
}
@@ -89,6 +95,7 @@ export function transformGemini(commands, skills, distDir, patterns = null) {
writeFile(path.join(geminiDir, 'GEMINI.md'), geminiMd);
const refInfo = refCount > 0 ? ` (${refCount} refs inlined)` : '';
console.log(`✓ Gemini: ${commands.length} commands (TOML), ${skills.length} skills (modular)${refInfo}`);
const prefixInfo = prefix ? ` [${prefix}prefixed]` : '';
console.log(`✓ Gemini${prefixInfo}: ${commands.length} commands (TOML), ${skills.length} skills (modular)${refInfo}`);
}
+10 -2
View File
@@ -50,12 +50,20 @@ export async function createProviderZip(providerDir, distDir, providerName) {
*/
export async function createAllZips(distDir) {
console.log('\n📦 Creating ZIP bundles...');
const providers = ['cursor', 'claude-code', 'gemini', 'codex'];
// Create unprefixed ZIPs
for (const provider of providers) {
const providerDir = path.join(distDir, provider);
await createProviderZip(providerDir, distDir, provider);
}
// Create prefixed ZIPs
console.log(' --- prefixed variants ---');
for (const provider of providers) {
const providerDir = path.join(distDir, `${provider}-prefixed`);
await createProviderZip(providerDir, distDir, `${provider}-prefixed`);
}
}