/** * multi-skills — Parser * * Parses `$skill_name` references from user input text. * Supports: * - $skill_name (standalone) * - Multi-skill: "Apply $skillA and $skillB together" * - Escaped: \$\ → literal $ */ /** Regex pattern for $skill_name references */ // Matches $ followed by a lowercase skill name (letters, digits, underscores, hyphens) // Not preceded by \ (escape). Skill names are lowercase by Pi/Agent Skills convention, // so uppercase shell variables like $PATH and $HOME are left alone. const SKILL_REF_RE = /(?(); return refs.filter((ref) => { if (seen.has(ref.name)) return false; seen.add(ref.name); return true; }); } /** * Replacement entry for replaceSkillRefs. */ export interface SkillReplacement { name: string; marker: string; } /** * Replace $skill_name references with markers. * * Sort by name length descending so longer names (e.g. "code-review") * are replaced before shorter ones (e.g. "code") to prevent partial * matches. */ export function replaceSkillRefs( text: string, replacements: SkillReplacement[], ): string { const sorted = [...replacements].sort( (a, b) => b.name.length - a.name.length, ); let result = text; for (const { name, marker } of sorted) { result = result.replace( new RegExp(`(?