import type { ClaudeCommand, ClaudeSkill } from "./types.js"; /** * Build the system-prompt sections describing currently loaded commands, * skills, and any collisions. Returns an empty string when there is * nothing relevant to inject. */ export function buildSystemPromptSections( commands: ClaudeCommand[], skills: ClaudeSkill[], collisions: Map, ): string { if (commands.length === 0 && skills.length === 0 && collisions.size === 0) { return ""; } const sections: string[] = []; if (commands.length > 0) { const commandList = commands .map(cmd => { const suffix = collisions.has(cmd.name) ? ` [CONFLICT with ${collisions.get(cmd.name)}]` : ""; return `- \`/${cmd.name}\`: ${cmd.description}${suffix}`; }) .join("\n"); sections.push( "## Claude Custom Commands\n" + "The following Claude CLI custom commands are loaded:\n\n" + `${commandList}\n\n` + "Use `/commandname` to invoke a command (e.g. `/test`, `/xyz:test1`). " + "Pass arguments after the command name, e.g. `/test my arguments`. " + "The `$ARGUMENTS` placeholder in command files will be replaced with the provided arguments.", ); } if (collisions.size > 0) { const collisionList = [...collisions.entries()] .map(([name, source]) => `- \`/${name}\`: already registered by ${source}`) .join("\n"); sections.push( "## Command Name Collisions\n" + "The following Claude command names conflict with existing commands and were not registered:\n\n" + `${collisionList}\n\n` + "Rename the .md file or move it to a subdirectory to change the command name. " + 'For example, rename "test.md" to "mytest.md" to get `/mytest` instead of `/test`.', ); } if (skills.length > 0) { const skillList = skills .map(s => `- \`/skill:${s.name}\`: ${s.description} (${s.dirPath})`) .join("\n"); sections.push( "## Claude Custom Skills\n" + "The following skills are available as pi slash commands:\n\n" + `${skillList}\n\n` + "Use `/skill:name` to invoke a skill. " + "Skills are also discoverable by the agent.", ); } return sections.join("\n\n"); }