@@ -26,6 +26,7 @@ import { firstRootPath } from '../sdk/server';
2626import type * as playwright from '../../../types/test' ;
2727import type { Config , ToolCapability } from '../config' ;
2828import type { ClientInfo } from '../sdk/server' ;
29+ import type { SessionConfig } from '../terminal/program' ;
2930
3031type ViewportSize = { width : number ; height : number } ;
3132
@@ -42,9 +43,7 @@ export type CLIOptions = {
4243 codegen ?: 'typescript' | 'none' ;
4344 config ?: string ;
4445 consoleLevel ?: 'error' | 'warning' | 'info' | 'debug' ;
45- daemon ?: string ;
46- daemonDataDir ?: string ;
47- daemonHeaded ?: boolean ;
46+ daemonSession ?: string ;
4847 device ?: string ;
4948 extension ?: boolean ;
5049 executablePath ?: string ;
@@ -107,22 +106,6 @@ export const defaultConfig: FullConfig = {
107106 } ,
108107} ;
109108
110- const defaultDaemonConfig = ( cliOptions : CLIOptions ) => mergeConfig ( defaultConfig , {
111- browser : {
112- userDataDir : '<daemon-data-dir>' ,
113- launchOptions : {
114- headless : ! cliOptions . daemonHeaded ,
115- } ,
116- contextOptions : {
117- viewport : cliOptions . daemonHeaded ? null : { width : 1280 , height : 720 } ,
118- } ,
119- } ,
120- outputMode : 'file' ,
121- snapshot : {
122- mode : 'full' ,
123- } ,
124- } ) ;
125-
126109type BrowserUserConfig = NonNullable < Config [ 'browser' ] > ;
127110
128111export type FullConfig = Config & {
@@ -146,32 +129,36 @@ export type FullConfig = Config & {
146129 navigation : number ;
147130 } ,
148131 skillMode ?: boolean ;
132+ configFile ?: string ;
133+ sessionConfig ?: SessionConfig ;
149134} ;
150135
151136export async function resolveConfig ( config : Config ) : Promise < FullConfig > {
152137 return mergeConfig ( defaultConfig , config ) ;
153138}
154139
155140export async function resolveCLIConfig ( cliOptions : CLIOptions ) : Promise < FullConfig > {
156- const configInFile = await loadConfig ( cliOptions . config ) ;
157141 const envOverrides = configFromEnv ( ) ;
142+ const daemonOverrides = await configForDaemonSession ( cliOptions ) ;
158143 const cliOverrides = configFromCLIOptions ( cliOptions ) ;
159- let result = cliOptions . daemon ? defaultDaemonConfig ( cliOptions ) : defaultConfig ;
144+ const configFile = cliOverrides . configFile ?? envOverrides . configFile ?? daemonOverrides . configFile ;
145+ const configInFile = await loadConfig ( configFile ) ;
146+
147+ let result = defaultConfig ;
160148 result = mergeConfig ( result , configInFile ) ;
149+ result = mergeConfig ( result , daemonOverrides ) ;
161150 result = mergeConfig ( result , envOverrides ) ;
162151 result = mergeConfig ( result , cliOverrides ) ;
163152
164- if ( cliOptions . daemon )
153+ if ( daemonOverrides . sessionConfig ) {
165154 result . skillMode = true ;
166155
167- if ( result . browser . userDataDir === '<daemon-data-dir>' ) {
168- // No custom value provided, use the daemon data dir.
169- const browserToken = result . browser . launchOptions ?. channel ?? result . browser ?. browserName ;
170- const userDataDir = `${ cliOptions . daemonDataDir } -${ browserToken } ` ;
171-
172- // Use default user profile with extension.
173- if ( ! result . extension )
156+ if ( ! result . extension && ! result . browser . userDataDir && daemonOverrides . sessionConfig . userDataDirPrefix ) {
157+ // No custom value provided, use the daemon data dir.
158+ const browserToken = result . browser . launchOptions ?. channel ?? result . browser ?. browserName ;
159+ const userDataDir = `${ daemonOverrides . sessionConfig . userDataDirPrefix } -${ browserToken } ` ;
174160 result . browser . userDataDir = userDataDir ;
161+ }
175162 }
176163
177164 if ( result . browser . browserName === 'chromium' && result . browser . launchOptions . chromiumSandbox === undefined ) {
@@ -181,7 +168,15 @@ export async function resolveCLIConfig(cliOptions: CLIOptions): Promise<FullConf
181168 result . browser . launchOptions . chromiumSandbox = true ;
182169 }
183170
171+ result . configFile = configFile ;
172+ result . sessionConfig = daemonOverrides . sessionConfig ;
173+
174+ // Daemon has different defaults.
175+ if ( result . sessionConfig && result . browser . launchOptions . headless !== false )
176+ result . browser . contextOptions . viewport ??= { width : 1280 , height : 720 } ;
177+
184178 await validateConfig ( result ) ;
179+
185180 return result ;
186181}
187182
@@ -202,7 +197,7 @@ async function validateConfig(config: FullConfig): Promise<void> {
202197 throw new Error ( 'saveVideo is not supported when sharedBrowserContext is true' ) ;
203198}
204199
205- export function configFromCLIOptions ( cliOptions : CLIOptions ) : Config {
200+ export function configFromCLIOptions ( cliOptions : CLIOptions ) : Config & { configFile ?: string } {
206201 let browserName : 'chromium' | 'firefox' | 'webkit' | undefined ;
207202 let channel : string | undefined ;
208203 switch ( cliOptions . browser ) {
@@ -269,7 +264,7 @@ export function configFromCLIOptions(cliOptions: CLIOptions): Config {
269264 if ( cliOptions . grantPermissions )
270265 contextOptions . permissions = cliOptions . grantPermissions ;
271266
272- const result : Config = {
267+ const config : Config = {
273268 browser : {
274269 browserName,
275270 isolated : cliOptions . isolated ,
@@ -313,10 +308,10 @@ export function configFromCLIOptions(cliOptions: CLIOptions): Config {
313308 } ,
314309 } ;
315310
316- return result ;
311+ return { ... config , configFile : cliOptions . config } ;
317312}
318313
319- function configFromEnv ( ) : Config {
314+ function configFromEnv ( ) : Config & { configFile ?: string } {
320315 const options : CLIOptions = { } ;
321316 options . allowedHosts = commaSeparatedList ( process . env . PLAYWRIGHT_MCP_ALLOWED_HOSTNAMES ) ;
322317 options . allowedOrigins = semicolonSeparatedList ( process . env . PLAYWRIGHT_MCP_ALLOWED_ORIGINS ) ;
@@ -364,6 +359,23 @@ function configFromEnv(): Config {
364359 return configFromCLIOptions ( options ) ;
365360}
366361
362+ async function configForDaemonSession ( cliOptions : CLIOptions ) : Promise < Config & { configFile ?: string , sessionConfig ?: SessionConfig } > {
363+ if ( ! cliOptions . daemonSession )
364+ return { } ;
365+
366+ const sessionConfig = await fs . promises . readFile ( cliOptions . daemonSession , 'utf-8' ) . then ( data => JSON . parse ( data ) as SessionConfig ) ;
367+ const config = configFromCLIOptions ( {
368+ config : sessionConfig . cli . config ,
369+ browser : sessionConfig . cli . browser ,
370+ isolated : sessionConfig . cli . isolated ,
371+ headless : ! sessionConfig . cli . headed ,
372+ extension : sessionConfig . cli . extension ,
373+ outputMode : 'file' ,
374+ snapshotMode : 'full' ,
375+ } ) ;
376+ return { ...config , sessionConfig } ;
377+ }
378+
367379async function loadConfig ( configFile : string | undefined ) : Promise < Config > {
368380 if ( ! configFile )
369381 return { } ;
0 commit comments