export function parseCommandArgs(argsString: string): string[] { const args: string[] = []; let current = ""; let inQuote: string | null = null; for (let i = 0; i < argsString.length; i++) { const char = argsString[i]; if (inQuote) { if (char === inQuote) { inQuote = null; } else { current += char; } } else if (char === '"' || char === "'") { inQuote = char; } else if (char === " " || char === "\t") { if (current) { args.push(current); current = ""; } } else { current += char; } } if (current) { args.push(current); } return args; } /** * Substitute argument placeholders in template content * Supports $1, $2, ... for positional args, $@ and $ARGUMENTS for all args * * Note: Replacement happens on the template string only. Argument values * containing patterns like $1, $@, or $ARGUMENTS are NOT recursively substituted. */ export function substituteArgs(content: string, args: string[]): string { let result = content; // Replace $1, $2, etc. with positional args FIRST (before wildcards) // This prevents wildcard replacement values containing $ patterns from being re-substituted result = result.replace(/\$(\d+)/g, (_, num) => { const index = parseInt(num, 10) - 1; return args[index] ?? ""; }); result = result.replace(/\$@\[(\d+)(?::(\d*)?)?\]/g, (_, startRaw: string, lengthRaw?: string) => { const start = Number.parseInt(startRaw, 10); if (!Number.isFinite(start) || start < 1) return ""; const startIndex = start - 1; if (startIndex >= args.length) return ""; if (lengthRaw === undefined || lengthRaw === "") { return args.slice(startIndex).join(" "); } const length = Number.parseInt(lengthRaw, 10); if (!Number.isFinite(length) || length <= 0) return ""; return args.slice(startIndex, startIndex + length).join(" "); }); // Pre-compute all args joined (optimization) const allArgs = args.join(" "); // Replace $ARGUMENTS with all args joined (new syntax, aligns with Claude, Codex, OpenCode) result = result.replaceAll("$ARGUMENTS", allArgs); // Replace $@ with all args joined (existing syntax) result = result.replaceAll("$@", allArgs); return result; }