From 9f96a331e3b30fde3ffd73c278cb4dd4bcd26c07 Mon Sep 17 00:00:00 2001 From: Kit Langton Date: Mon, 26 Oct 2026 10:01:47 -0700 Subject: [PATCH] fix(core): stop custom commands from overwriting $0 and re-filling $ARGUMENTS you typed (#59198) --- packages/core/src/config/plugin/command.ts | 7 ++++--- packages/core/test/config/command.test.ts | 15 +++++++++++++++ 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/packages/core/src/config/plugin/command.ts b/packages/core/src/config/plugin/command.ts index 9d739ac8c51..c13ff4a5b02 100644 --- a/packages/core/src/config/plugin/command.ts +++ b/packages/core/src/config/plugin/command.ts @@ -193,14 +193,14 @@ function evaluateTemplate( const args = parseArguments(input) const placeholders = template.match(placeholderRegex) ?? [] const last = Math.max(0, ...placeholders.map((item) => Number(item.slice(1)))) - const expanded = template.replaceAll(placeholderRegex, (_, index) => { + const withArguments = template.replaceAll(argumentRegex, (match, index) => { + if (match === "$ARGUMENTS") return input const position = Number(index) const argIndex = position - 1 if (argIndex >= args.length) return "" if (position === last) return args.slice(argIndex).join(" ") return args[argIndex] }) - const withArguments = expanded.replaceAll("$ARGUMENTS", () => input) const text = placeholders.length === 0 && !template.includes("$ARGUMENTS") && input.trim() ? `${withArguments}\n\n${input}`.trim() @@ -239,6 +239,7 @@ function parseArguments(input: string) { } const argsRegex = /(?:\[Image\s+\d+\]|"[^"]*"|'[^']*'|[^\s"']+)/gi -const placeholderRegex = /\$(\d+)/g +const placeholderRegex = /\$([1-9]\d*)/g +const argumentRegex = /\$(?:ARGUMENTS|([1-9]\d*))/g const quoteTrimRegex = /^["']|["']$/g const shellRegex = /!`([^`]+)`/g diff --git a/packages/core/test/config/command.test.ts b/packages/core/test/config/command.test.ts index 9d80adbfb75..cf77c83690c 100644 --- a/packages/core/test/config/command.test.ts +++ b/packages/core/test/config/command.test.ts @@ -89,6 +89,21 @@ describe("ConfigCommandPlugin.Plugin", () => { input: '"alpha beta" gamma delta', expected: "First alpha beta. Rest gamma delta.", }, + { + template: "Run awk '{print $0}' on $1.", + input: "app.log", + expected: "Run awk '{print $0}' on app.log.", + }, + { + template: "Run awk '{print $0}'.", + input: "app.log", + expected: "Run awk '{print $0}'.\n\napp.log", + }, + { + template: "First $1. Rest $2.", + input: '"$ARGUMENTS" tail', + expected: "First $ARGUMENTS. Rest tail.", + }, { template: "$ARGUMENTS / $ARGUMENTS", input: "$& $$", expected: "$& $$ / $& $$" }, ]) { it.live(`interpolates ${JSON.stringify(item.template)} with literal input ${JSON.stringify(item.input)}`, () =>