Browser: support non-Chrome existing-session profiles via userDataDir (#48170)

Merged via squash.

Prepared head SHA: e490035a24
Co-authored-by: velvet-shark <126378+velvet-shark@users.noreply.github.com>
Co-authored-by: velvet-shark <126378+velvet-shark@users.noreply.github.com>
Reviewed-by: @velvet-shark
This commit is contained in:
Radek Sienkiewicz
2026-03-16 14:21:22 +01:00
committed by GitHub
parent 3e360ec8cb
commit 7deb543624
34 changed files with 650 additions and 126 deletions

View File

@@ -91,6 +91,42 @@ describe("browser manage output", () => {
expect(output).not.toContain("cdpUrl:");
});
it("shows configured userDataDir for existing-session status", async () => {
mocks.callBrowserRequest.mockImplementation(async (_opts: unknown, req: { path?: string }) =>
req.path === "/"
? {
enabled: true,
profile: "brave-live",
driver: "existing-session",
transport: "chrome-mcp",
running: true,
cdpReady: true,
cdpHttp: true,
pid: 4321,
cdpPort: null,
cdpUrl: null,
chosenBrowser: null,
userDataDir: "/Users/test/Library/Application Support/BraveSoftware/Brave-Browser",
color: "#FB542B",
headless: false,
noSandbox: false,
executablePath: null,
attachOnly: true,
}
: {},
);
const program = createProgram();
await program.parseAsync(["browser", "--browser-profile", "brave-live", "status"], {
from: "user",
});
const output = mocks.runtimeLog.mock.calls.at(-1)?.[0] as string;
expect(output).toContain(
"userDataDir: /Users/test/Library/Application Support/BraveSoftware/Brave-Browser",
);
});
it("shows chrome-mcp transport in browser profiles output", async () => {
mocks.callBrowserRequest.mockImplementation(async (_opts: unknown, req: { path?: string }) =>
req.path === "/profiles"
@@ -131,6 +167,7 @@ describe("browser manage output", () => {
transport: "chrome-mcp",
cdpPort: null,
cdpUrl: null,
userDataDir: null,
color: "#00AA00",
isRemote: false,
}

View File

@@ -116,9 +116,13 @@ function formatBrowserConnectionSummary(params: {
isRemote?: boolean;
cdpPort?: number | null;
cdpUrl?: string | null;
userDataDir?: string | null;
}): string {
if (usesChromeMcpTransport(params)) {
return "transport: chrome-mcp";
const userDataDir = params.userDataDir ? shortenHomePath(params.userDataDir) : null;
return userDataDir
? `transport: chrome-mcp, userDataDir: ${userDataDir}`
: "transport: chrome-mcp";
}
if (params.isRemote) {
return `cdpUrl: ${params.cdpUrl ?? "(unset)"}`;
@@ -155,7 +159,9 @@ export function registerBrowserManageCommands(
`cdpPort: ${status.cdpPort ?? "(unset)"}`,
`cdpUrl: ${redactCdpUrl(status.cdpUrl ?? `http://127.0.0.1:${status.cdpPort}`)}`,
]
: []),
: status.userDataDir
? [`userDataDir: ${shortenHomePath(status.userDataDir)}`]
: []),
`browser: ${status.chosenBrowser ?? "unknown"}`,
`detectedBrowser: ${status.detectedBrowser ?? "unknown"}`,
`detectedPath: ${detectedDisplay}`,
@@ -455,9 +461,19 @@ export function registerBrowserManageCommands(
.requiredOption("--name <name>", "Profile name (lowercase, numbers, hyphens)")
.option("--color <hex>", "Profile color (hex format, e.g. #0066CC)")
.option("--cdp-url <url>", "CDP URL for remote Chrome (http/https)")
.option("--user-data-dir <path>", "User data dir for existing-session Chromium attach")
.option("--driver <driver>", "Profile driver (openclaw|existing-session). Default: openclaw")
.action(
async (opts: { name: string; color?: string; cdpUrl?: string; driver?: string }, cmd) => {
async (
opts: {
name: string;
color?: string;
cdpUrl?: string;
userDataDir?: string;
driver?: string;
},
cmd,
) => {
const parent = parentOpts(cmd);
await runBrowserCommand(async () => {
const result = await callBrowserRequest<BrowserCreateProfileResult>(
@@ -469,6 +485,7 @@ export function registerBrowserManageCommands(
name: opts.name,
color: opts.color,
cdpUrl: opts.cdpUrl,
userDataDir: opts.userDataDir,
driver: opts.driver === "existing-session" ? "existing-session" : undefined,
},
},
@@ -481,8 +498,8 @@ export function registerBrowserManageCommands(
defaultRuntime.log(
info(
`🦞 Created profile "${result.profile}"\n${loc}\n color: ${result.color}${
opts.driver === "existing-session" ? "\n driver: existing-session" : ""
}`,
result.userDataDir ? `\n userDataDir: ${shortenHomePath(result.userDataDir)}` : ""
}${opts.driver === "existing-session" ? "\n driver: existing-session" : ""}`,
),
);
});