Skip to content

Add --proxy flag for routing the browser through a Kernel proxy#56

Merged
rgarcia merged 2 commits into
mainfrom
hypeship/cli-proxy-flag
Jul 10, 2026
Merged

Add --proxy flag for routing the browser through a Kernel proxy#56
rgarcia merged 2 commits into
mainfrom
hypeship/cli-proxy-flag

Conversation

@rgarcia

@rgarcia rgarcia commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds --proxy <id-or-name> to the cua CLI, mirroring --profile's selector ergonomics without the auto-create behavior:

  • Resolution: try proxies.retrieve(selector) as an id, fall back to a unique name match from proxies.list(). Ambiguous names and unknown selectors are errors — proxies require type/location/credential configuration, so a bare name is never enough to create one.
  • Applies to one-shot subcommands (including the model-free ones) and cua session start; named sessions persist the resolved proxy_id in their metadata (visible via cua session show), and later -s attaches inherit the browser's proxy naturally.
  • Help text and the cua-cli skill doc updated.

Testing

  • Unit tests for resolveProxyId (id hit, unique-name fallback, ambiguous name, not-found, non-404 propagation).
  • The browsers.create passthrough is type-checked (proxy_id is a typed param).
  • Full typecheck + ai/agent/cli suites green locally (one pre-existing env-dependent api-keys test failure when a real GOOGLE_API_KEY is present).
  • Not exercised against a live Kernel proxy.

Release

Bumps @onkernel/cua-cli to 0.3.1. After merge, tag the merge commit with cua-cli/v0.3.1 to publish. No changes to cua-ai/cua-agent, so their versions and pinned deps are untouched.


Note

Low Risk
Additive CLI option and browser create parameter with explicit lookup errors; no auth or data-model changes beyond optional named-session metadata.

Overview
Adds --proxy <name|id> so cua can route new Kernel browsers through an existing proxy, with the same id-or-name ergonomics as --profile but no auto-create for unknown names.

Resolution goes through new resolveProxyId: try proxies.retrieve, then a unique proxies.list name match; ambiguous or missing selectors fail with a clear error. The resolved id is passed as proxy_id on browsers.create for one-shot runs and for cua session start, and proxy_id is stored in named-session metadata (visible via cua session show). Re-attaching with -s reuses the browser and its proxy.

Also bumps @onkernel/cua-cli to 0.3.1, updates help and the cua-cli skill doc, and adds unit tests for resolveProxyId.

Reviewed by Cursor Bugbot for commit 8d6d83b. Bugbot is set up for automated code reviews on this repo. Configure here.

rgarcia added 2 commits July 10, 2026 15:24
Accepts a proxy id or name, resolved via proxies.retrieve with a
list-by-name fallback; ambiguous names and unknown selectors are errors
(proxies are never auto-created, unlike --profile). Applies to one-shot
subcommands and session start; named sessions persist the resolved
proxy_id in their metadata.
@rgarcia rgarcia marked this pull request as ready for review July 10, 2026 16:07
@rgarcia rgarcia merged commit d5b0128 into main Jul 10, 2026
6 checks passed

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

Bugbot Autofix prepared a fix for the issue found in the latest run.

  • ✅ Fixed: Retrieve success falls through names
    • resolveProxyId now treats a successful retrieve without an id as an error and no longer falls through to name-based list matching, with a regression test added for that path.

Create PR

Or push these changes by commenting:

@cursor push a003234ee5
Preview (a003234ee5)
diff --git a/packages/cli/src/harness-browser.ts b/packages/cli/src/harness-browser.ts
--- a/packages/cli/src/harness-browser.ts
+++ b/packages/cli/src/harness-browser.ts
@@ -65,7 +65,10 @@
 	if (!trimmed) throw new Error("proxy selector is empty");
 	try {
 		const existing = await client.proxies.retrieve(trimmed);
-		if (existing.id) return existing.id;
+		if (!existing.id) {
+			throw new Error(`proxy "${trimmed}" lookup returned no id`);
+		}
+		return existing.id;
 	} catch (err) {
 		if (!(err instanceof NotFoundError)) {
 			throw new Error(`looking up proxy "${trimmed}": ${(err as Error).message}`, { cause: err });

diff --git a/packages/cli/test/harness-browser.test.ts b/packages/cli/test/harness-browser.test.ts
--- a/packages/cli/test/harness-browser.test.ts
+++ b/packages/cli/test/harness-browser.test.ts
@@ -22,6 +22,19 @@
 		await expect(resolveProxyId(client, "proxy_abc")).resolves.toBe("proxy_abc");
 	});
 
+	it("does not fall back to name matching when retrieve succeeds without an id", async () => {
+		let listCalled = false;
+		const client = fakeClient({
+			retrieve: async () => ({}),
+			list: async () => {
+				listCalled = true;
+				return [{ id: "proxy_1", name: "proxy_abc" }];
+			},
+		});
+		await expect(resolveProxyId(client, "proxy_abc")).rejects.toThrow(/looking up proxy/);
+		expect(listCalled).toBe(false);
+	});
+
 	it("falls back to a unique name match from the proxy list", async () => {
 		const client = fakeClient({ list: async () => [{ id: "proxy_1", name: "residential-us" }, { id: "proxy_2", name: "other" }] });
 		await expect(resolveProxyId(client, "residential-us")).resolves.toBe("proxy_1");

You can send follow-ups to the cloud agent here.

Reviewed by Cursor Bugbot for commit 8d6d83b. Configure here.

const matches = proxies.filter((proxy) => proxy.name === trimmed && proxy.id);
if (matches.length === 1) return matches[0]!.id!;
if (matches.length > 1) throw new Error(`proxy name "${trimmed}" is ambiguous (${matches.length} proxies); pass the proxy id`);
throw new Error(`proxy "${trimmed}" was not found; create one first (e.g. kernel proxies create)`);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Retrieve success falls through names

Medium Severity

In resolveProxyId, when proxies.retrieve succeeds but the response has no truthy id, resolution continues as if the lookup failed and tries a name match via proxies.list(). That can route the browser through the wrong proxy or report not found even though retrieve succeeded.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 8d6d83b. Configure here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant