Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 16 additions & 3 deletions src/hosted/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export interface HostedManifestCache {

export type LocalBrowserConfig =
| { kind: 'cloak' }
| { kind: 'chrome'; executablePath: string; syncToChrome?: boolean }
| { kind: 'chrome'; executablePath: string; chromeProfile?: string; syncToChrome?: boolean }
| { kind: 'slab' }
| { kind: 'custom'; executablePath: string };

Expand Down Expand Up @@ -208,10 +208,23 @@ function readCredentialBackend(value: unknown): HostedCredentialBackend | undefi

function readLocalBrowser(value: unknown): LocalBrowserConfig {
if (value && typeof value === 'object') {
const browser = value as { kind?: unknown; executablePath?: unknown; syncToChrome?: unknown };
const browser = value as {
kind?: unknown;
executablePath?: unknown;
chromeProfile?: unknown;
syncToChrome?: unknown;
};
if (browser.kind === 'cloak' || browser.kind === 'slab') return { kind: browser.kind };
if (browser.kind === 'chrome' && typeof browser.executablePath === 'string' && path.isAbsolute(browser.executablePath)) {
return { kind: 'chrome', executablePath: browser.executablePath, ...(browser.syncToChrome === true ? { syncToChrome: true } : {}) };
const chromeProfile = typeof browser.chromeProfile === 'string' && browser.chromeProfile.trim()
? browser.chromeProfile.trim()
: undefined;
return {
kind: 'chrome',
executablePath: browser.executablePath,
...(chromeProfile ? { chromeProfile } : {}),
...(browser.syncToChrome === true ? { syncToChrome: true } : {}),
};
}
if (browser.kind === 'custom' && typeof browser.executablePath === 'string' && path.isAbsolute(browser.executablePath)) {
return { kind: 'custom', executablePath: browser.executablePath };
Expand Down
27 changes: 26 additions & 1 deletion src/hosted/setup.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { Writable } from 'node:stream';
import { fileURLToPath } from 'node:url';
import { afterEach, describe, expect, it, vi } from 'vitest';
import { getConfigPath, makeLocalConfig, saveWebcmdConfig } from './config.js';
import { runHostedSetup } from './setup.js';
import { getSetupStatus, runHostedSetup } from './setup.js';
import type { SlabSetupStatus } from '../slab/status.js';

let tempDir: string | undefined;
Expand Down Expand Up @@ -188,6 +188,31 @@ describe('webcmd setup', () => {
});
});

it('persists and reports the selected Chrome profile in setup status', async () => {
tempDir = await mkdtemp(join(tmpdir(), 'webcmd-setup-chrome-profile-status-'));
const env = { WEBCMD_CONFIG_DIR: tempDir } as NodeJS.ProcessEnv;
const executablePath = '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome';

await expect(runHostedSetup({
env,
argv: ['--browser', 'chrome', '--chrome-profile', 'Profile 15'],
isTTY: false,
resolveGoogleChromeExecutable: async () => executablePath,
fetchDaemonStatus: async () => null,
write: () => undefined,
})).resolves.toBe(0);

expect(JSON.parse(await readFile(getConfigPath({ env }), 'utf8'))).toMatchObject({
mode: 'local',
browser: { kind: 'chrome', executablePath, chromeProfile: 'Profile 15' },
});
expect(await getSetupStatus({ env })).toMatchObject({
configured: true,
mode: 'local',
browser: { kind: 'chrome', executablePath, chromeProfile: 'Profile 15' },
});
});

it('explains how to install Google Chrome when it is unavailable', async () => {
tempDir = await mkdtemp(join(tmpdir(), 'webcmd-setup-chrome-missing-'));
const messages: string[] = [];
Expand Down
6 changes: 4 additions & 2 deletions src/hosted/setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -146,9 +146,11 @@ export async function runHostedSetup(io: SetupIo = {}): Promise<number> {
const before = await (io.fetchDaemonStatus ?? fetchDaemonStatus)();
try {
const selected = await validateLocalBrowser(browser, io, chromeDiscovery, syncToChrome);
const chromeProfile = selected.kind === 'chrome' ? parsed.chromeProfile?.trim() : undefined;
const persistedSelected = selected.kind === 'chrome' && chromeProfile ? { ...selected, chromeProfile } : selected;
if (selected.kind === 'chrome') await maybeImportChromeCookies(parsed, io, interactive, ask, write);
(io.saveConfig ?? saveWebcmdConfig)(makeLocalConfig(io.now?.() ?? new Date(), selected), io);
if (before) await restartConfiguredDaemon(selected, io);
(io.saveConfig ?? saveWebcmdConfig)(makeLocalConfig(io.now?.() ?? new Date(), persistedSelected), io);
if (before) await restartConfiguredDaemon(persistedSelected, io);
} catch (err) {
const message = err instanceof Error ? err.message : String(err);
await write(`Local browser setup failed: ${message}\n`);
Expand Down
Loading