From eb8baa46afb0ca53893badfc839c474aebe656f5 Mon Sep 17 00:00:00 2001 From: VoidChecksum <89574102+VoidChecksum@users.noreply.github.com> Date: Sun, 5 Apr 2026 05:26:13 +0200 Subject: [PATCH] fix: strip shell comment lines before parsing claude_args (#1055) shell-quote treats # as a shell comment character, swallowing all subsequent content including flags on new lines. Strip comment lines (lines starting with #) before passing input to shell-quote. Fixes #802 Co-authored-by: VoidChecksum --- base-action/src/parse-sdk-options.ts | 16 +++++++++- base-action/test/parse-sdk-options.test.ts | 36 ++++++++++++++++++++++ 2 files changed, 51 insertions(+), 1 deletion(-) diff --git a/base-action/src/parse-sdk-options.ts b/base-action/src/parse-sdk-options.ts index 5576117..ec65b8f 100644 --- a/base-action/src/parse-sdk-options.ts +++ b/base-action/src/parse-sdk-options.ts @@ -79,6 +79,20 @@ function mergeMcpConfigs(configValues: string[]): string { return JSON.stringify(merged); } +/** + * Strip comment lines from a shell argument string. + * Lines whose first non-whitespace character is `#` are removed entirely. + * Inline `#` within a line (e.g. inside a quoted value) is left untouched + * because shell-quote handles quoting — we only need to remove full comment lines + * before shell-quote sees them. + */ +function stripShellComments(input: string): string { + return input + .split("\n") + .filter((line) => !line.trim().startsWith("#")) + .join("\n"); +} + /** * Parse claudeArgs string into extraArgs record for SDK pass-through * The SDK/CLI will handle --mcp-config, --json-schema, etc. @@ -92,7 +106,7 @@ function parseClaudeArgsToExtraArgs( if (!claudeArgs?.trim()) return {}; const result: Record = {}; - const args = parseShellArgs(claudeArgs).filter( + const args = parseShellArgs(stripShellComments(claudeArgs)).filter( (arg): arg is string => typeof arg === "string", ); diff --git a/base-action/test/parse-sdk-options.test.ts b/base-action/test/parse-sdk-options.test.ts index e76e66c..26ff288 100644 --- a/base-action/test/parse-sdk-options.test.ts +++ b/base-action/test/parse-sdk-options.test.ts @@ -313,6 +313,42 @@ describe("parseSdkOptions", () => { }); }); + describe("shell comment stripping", () => { + test("should parse flags before and after a comment line", () => { + const options: ClaudeOptions = { + claudeArgs: "--model 'claude-haiku'\n# comment\n--allowed-tools 'Edit'", + }; + + const result = parseSdkOptions(options); + + expect(result.sdkOptions.extraArgs?.["model"]).toBe("claude-haiku"); + expect(result.sdkOptions.allowedTools).toEqual(["Edit"]); + }); + + test("should parse flags correctly when no comments are present", () => { + const options: ClaudeOptions = { + claudeArgs: "--model 'claude-haiku'", + }; + + const result = parseSdkOptions(options); + + expect(result.sdkOptions.extraArgs?.["model"]).toBe("claude-haiku"); + }); + + test("should not strip inline # that appears inside a quoted value", () => { + const options: ClaudeOptions = { + claudeArgs: "--model 'claude-haiku' --prompt 'use color #ff0000'", + }; + + const result = parseSdkOptions(options); + + expect(result.sdkOptions.extraArgs?.["model"]).toBe("claude-haiku"); + expect(result.sdkOptions.extraArgs?.["prompt"]).toBe( + "use color #ff0000", + ); + }); + }); + describe("environment variables passthrough", () => { test("should include OTEL environment variables in sdkOptions.env", () => { // Set up test environment variables