-
Notifications
You must be signed in to change notification settings - Fork 1.7k
feat: add Launch Args setting for Claude provider #1971
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
juliusmarminge
merged 8 commits into
pingdotgg:main
from
akarabach:feat/claude-chrome-integration
Apr 15, 2026
Merged
Changes from 5 commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
9a77e55
feat: add Enable Chrome setting for Claude provider
akarabach 9873c01
feat: launch args instead of specific chrome flag
akarabach cfefd47
feat: use normal string with spaces
akarabach 1730291
feat: fix parse args twice
akarabach 5533364
feat: common parser of cli args, unit tests
akarabach 459c130
feat: fixes cursor comment add boolean flags parameter
akarabach 4931df9
Merge branch 'main' into feat/claude-chrome-integration
akarabach be6cca1
Merge origin/main into t3code/pr-1971/feat/claude-chrome-integration
juliusmarminge File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3219,3 +3219,4 @@ describe("ClaudeAdapterLive", () => { | |
| ); | ||
| }); | ||
| }); | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,105 @@ | ||
| import { describe, expect, it } from "vitest"; | ||
|
|
||
| import { parseCliArgs } from "./cliArgs.ts"; | ||
|
|
||
| describe("parseCliArgs", () => { | ||
| it("returns empty result for empty string", () => { | ||
| expect(parseCliArgs("")).toEqual({ flags: {}, positionals: [] }); | ||
| }); | ||
|
|
||
| it("returns empty result for whitespace-only string", () => { | ||
| expect(parseCliArgs(" ")).toEqual({ flags: {}, positionals: [] }); | ||
| }); | ||
|
|
||
| it("returns empty result for empty array", () => { | ||
| expect(parseCliArgs([])).toEqual({ flags: {}, positionals: [] }); | ||
| }); | ||
|
|
||
| it("parses --chrome boolean flag", () => { | ||
| expect(parseCliArgs("--chrome")).toEqual({ | ||
| flags: { chrome: null }, | ||
| positionals: [], | ||
| }); | ||
| }); | ||
|
|
||
| it("parses --chrome with --verbose", () => { | ||
| expect(parseCliArgs("--chrome --verbose")).toEqual({ | ||
| flags: { chrome: null, verbose: null }, | ||
| positionals: [], | ||
| }); | ||
| }); | ||
|
|
||
| it("parses --effort with a value", () => { | ||
| expect(parseCliArgs("--effort high")).toEqual({ | ||
| flags: { effort: "high" }, | ||
| positionals: [], | ||
| }); | ||
| }); | ||
|
|
||
| it("parses --chrome --effort high --debug", () => { | ||
| expect(parseCliArgs("--chrome --effort high --debug")).toEqual({ | ||
| flags: { chrome: null, effort: "high", debug: null }, | ||
| positionals: [], | ||
| }); | ||
| }); | ||
|
|
||
| it("parses --model with full model name", () => { | ||
| expect(parseCliArgs("--model claude-sonnet-4-6")).toEqual({ | ||
| flags: { model: "claude-sonnet-4-6" }, | ||
| positionals: [], | ||
| }); | ||
| }); | ||
|
|
||
| it("parses --append-system-prompt with value and --chrome", () => { | ||
| expect(parseCliArgs("--append-system-prompt always-think-step-by-step --chrome")).toEqual({ | ||
| flags: { "append-system-prompt": "always-think-step-by-step", chrome: null }, | ||
| positionals: [], | ||
| }); | ||
| }); | ||
|
|
||
| it("parses --max-budget-usd with numeric value", () => { | ||
| expect(parseCliArgs("--chrome --max-budget-usd 5.00")).toEqual({ | ||
| flags: { chrome: null, "max-budget-usd": "5.00" }, | ||
| positionals: [], | ||
| }); | ||
| }); | ||
|
|
||
| it("parses --effort=high syntax", () => { | ||
| expect(parseCliArgs("--effort=high")).toEqual({ | ||
| flags: { effort: "high" }, | ||
| positionals: [], | ||
| }); | ||
| }); | ||
|
|
||
| it("parses --key=value mixed with boolean flags", () => { | ||
| expect(parseCliArgs("--chrome --model=claude-sonnet-4-6 --debug")).toEqual({ | ||
| flags: { chrome: null, model: "claude-sonnet-4-6", debug: null }, | ||
| positionals: [], | ||
| }); | ||
| }); | ||
|
|
||
| it("collects positional arguments", () => { | ||
| expect(parseCliArgs("1.2.3")).toEqual({ | ||
| flags: {}, | ||
| positionals: ["1.2.3"], | ||
| }); | ||
| }); | ||
|
|
||
| it("collects positionals mixed with flags (argv array)", () => { | ||
| expect(parseCliArgs(["1.2.3", "--root", "/path", "--github-output"])).toEqual({ | ||
| flags: { root: "/path", "github-output": null }, | ||
| positionals: ["1.2.3"], | ||
| }); | ||
| }); | ||
|
|
||
| it("handles extra whitespace between tokens", () => { | ||
| expect(parseCliArgs(" --chrome --verbose ")).toEqual({ | ||
| flags: { chrome: null, verbose: null }, | ||
| positionals: [], | ||
| }); | ||
| }); | ||
|
|
||
| it("ignores bare -- with no flag name", () => { | ||
| expect(parseCliArgs("--")).toEqual({ flags: {}, positionals: [] }); | ||
| }); | ||
| }); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,62 @@ | ||
| export interface ParsedCliArgs { | ||
| readonly flags: Record<string, string | null>; | ||
| readonly positionals: string[]; | ||
| } | ||
|
|
||
| /** | ||
| * Parse CLI-style arguments into flags and positionals. | ||
| * | ||
| * Accepts a string (split by whitespace) or a pre-split argv array. | ||
| * Supports `--key value`, `--key=value`, and `--flag` (boolean) syntax. | ||
| * | ||
| * parseCliArgs("") | ||
| * → { flags: {}, positionals: [] } | ||
| * | ||
| * parseCliArgs("--chrome") | ||
| * → { flags: { chrome: null }, positionals: [] } | ||
| * | ||
| * parseCliArgs("--chrome --effort high") | ||
| * → { flags: { chrome: null, effort: "high" }, positionals: [] } | ||
| * | ||
| * parseCliArgs("--effort=high") | ||
| * → { flags: { effort: "high" }, positionals: [] } | ||
| * | ||
| * parseCliArgs(["1.2.3", "--root", "/path", "--github-output"]) | ||
| * → { flags: { root: "/path", "github-output": null }, positionals: ["1.2.3"] } | ||
| */ | ||
| export function parseCliArgs(args: string | readonly string[]): ParsedCliArgs { | ||
| const tokens = | ||
| typeof args === "string" ? args.trim().split(/\s+/).filter(Boolean) : Array.from(args); | ||
|
akarabach marked this conversation as resolved.
|
||
|
|
||
| const flags: Record<string, string | null> = {}; | ||
| const positionals: string[] = []; | ||
|
|
||
| for (let i = 0; i < tokens.length; i++) { | ||
| const token = tokens[i]!; | ||
|
|
||
| if (token.startsWith("--")) { | ||
| const rest = token.slice(2); | ||
| if (!rest) continue; | ||
|
|
||
| // Handle --key=value syntax | ||
| const eqIndex = rest.indexOf("="); | ||
| if (eqIndex !== -1) { | ||
| flags[rest.slice(0, eqIndex)] = rest.slice(eqIndex + 1); | ||
| continue; | ||
| } | ||
|
|
||
| // Handle --key value or --flag (boolean) | ||
| const next = tokens[i + 1]; | ||
| if (next !== undefined && !next.startsWith("--")) { | ||
| flags[rest] = next; | ||
| i++; | ||
| } else { | ||
| flags[rest] = null; | ||
| } | ||
| } else { | ||
| positionals.push(token); | ||
| } | ||
| } | ||
|
|
||
| return { flags, positionals }; | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,63 @@ | ||
| import { describe, expect, it } from "vitest"; | ||
|
|
||
| import { parseArgs } from "./update-release-package-versions.ts"; | ||
|
|
||
| describe("parseArgs", () => { | ||
| it("parses version only", () => { | ||
| expect(parseArgs(["1.2.3"])).toEqual({ | ||
| version: "1.2.3", | ||
| rootDir: undefined, | ||
| writeGithubOutput: false, | ||
| }); | ||
| }); | ||
|
|
||
| it("parses version with --root", () => { | ||
| expect(parseArgs(["1.2.3", "--root", "/path"])).toEqual({ | ||
| version: "1.2.3", | ||
| rootDir: "/path", | ||
| writeGithubOutput: false, | ||
| }); | ||
| }); | ||
|
|
||
| it("parses version with --github-output", () => { | ||
| expect(parseArgs(["1.2.3", "--github-output"])).toEqual({ | ||
| version: "1.2.3", | ||
| rootDir: undefined, | ||
| writeGithubOutput: true, | ||
| }); | ||
| }); | ||
|
|
||
| it("parses version with --root and --github-output", () => { | ||
| expect(parseArgs(["1.2.3", "--root", "/path", "--github-output"])).toEqual({ | ||
| version: "1.2.3", | ||
| rootDir: "/path", | ||
| writeGithubOutput: true, | ||
| }); | ||
| }); | ||
|
|
||
| it("accepts flags before the version positional", () => { | ||
| expect(parseArgs(["--github-output", "--root", "/path", "1.2.3"])).toEqual({ | ||
| version: "1.2.3", | ||
| rootDir: "/path", | ||
| writeGithubOutput: true, | ||
| }); | ||
| }); | ||
|
|
||
| it("throws on missing version", () => { | ||
| expect(() => parseArgs([])).toThrow("Usage:"); | ||
| }); | ||
|
|
||
| it("throws on duplicate version", () => { | ||
| expect(() => parseArgs(["1.2.3", "2.0.0"])).toThrow( | ||
| "Only one release version can be provided.", | ||
| ); | ||
| }); | ||
|
|
||
| it("throws on unknown flag", () => { | ||
| expect(() => parseArgs(["1.2.3", "--unknown"])).toThrow("Unknown argument: --unknown"); | ||
| }); | ||
|
|
||
| it("throws on --root without value", () => { | ||
| expect(() => parseArgs(["1.2.3", "--root"])).toThrow("Missing value for --root."); | ||
| }); | ||
| }); |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if I enter some invalid value in the input box there's no indication of that and they'll be silently ignored?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, but Claude won't be able to start.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I considered a few approaches for validating the launch args input and decided to keep it as a plain text field without validation. Here's the reasoning:
Runtime extraction - run
claude --helpwhen the user opens settings, parse the output to get valid flags, validate against them. Problems: --help output is unstructured text (no --json option), parsing is fragile across CLI versions, and we'd need to filter out flags the SDK already handles (--model, --effort, --resume, etc.) to avoid conflicts.Hardcoded flag list - maintain a static list of valid Claude CLI flags. Problems: Claude CLI updates frequently, the list would go stale fast, and false negatives on new valid flags would be worse than no validation.