@@ -47,8 +47,7 @@ export type SessionConfig = {
4747
4848type ClientInfo = {
4949 version : string ;
50- installationDir : string ;
51- installationDirHash : string ;
50+ workspaceDirHash : string ;
5251 daemonProfilesDir : string ;
5352} ;
5453
@@ -249,12 +248,15 @@ to restart the session daemon.`);
249248 console . log ( formatWithGap ( `- playwright-cli${ sessionOption } close` , `# to stop when done.` ) ) ;
250249 console . log ( formatWithGap ( `- playwright-cli${ sessionOption } open [options]` , `# to reopen with new config.` ) ) ;
251250 console . log ( formatWithGap ( `- playwright-cli${ sessionOption } delete-data` , `# to delete session data.` ) ) ;
251+ console . log ( `---` ) ;
252+ console . log ( `` ) ;
252253
253254 // Wait for the socket to become available with retries.
254- const maxRetries = 50 ;
255- const retryDelay = 100 ; // ms
256- for ( let i = 0 ; i < maxRetries ; i ++ ) {
257- await new Promise ( resolve => setTimeout ( resolve , retryDelay ) ) ;
255+ const retryDelay = [ 100 , 200 , 400 ] ; // ms
256+ let totalWaited = 0 ;
257+ for ( let i = 0 ; i < 10 ; i ++ ) {
258+ await new Promise ( resolve => setTimeout ( resolve , retryDelay [ i ] || 1000 ) ) ;
259+ totalWaited += retryDelay [ i ] || 1000 ;
258260 try {
259261 const { socket } = await this . _connect ( ) ;
260262 if ( socket )
@@ -268,7 +270,7 @@ to restart the session daemon.`);
268270 const outData = await fs . promises . readFile ( outLog , 'utf-8' ) . catch ( ( ) => '' ) ;
269271 const errData = await fs . promises . readFile ( errLog , 'utf-8' ) . catch ( ( ) => '' ) ;
270272
271- console . error ( `Failed to connect to daemon at ${ this . _config . socketPath } after ${ maxRetries * retryDelay } ms` ) ;
273+ console . error ( `Failed to connect to daemon at ${ this . _config . socketPath } after ${ totalWaited } ms` ) ;
272274 if ( outData . length )
273275 console . log ( outData ) ;
274276 if ( errData . length )
@@ -347,11 +349,9 @@ class SessionManager {
347349 const sessionName = this . _resolveSessionName ( args . session ) ;
348350 const session = this . sessions . get ( sessionName ) ;
349351 if ( ! session ) {
350- const configFromArgs = sessionConfigFromArgs ( this . clientInfo , sessionName , args ) ;
351- const formattedArgs = configToFormattedArgs ( configFromArgs . cli ) ;
352- console . log ( `The session '${ sessionName } ' is not open, please run open first:` ) ;
352+ console . log ( `The session '${ sessionName } ' is not open, please run open first` ) ;
353353 console . log ( '' ) ;
354- console . log ( ` playwright-cli${ sessionName !== 'default' ? ` --session=${ sessionName } ` : '' } open ${ formattedArgs . join ( ' ' ) } ` ) ;
354+ console . log ( ` playwright-cli${ sessionName !== 'default' ? ` --session=${ sessionName } ` : '' } open [params] ` ) ;
355355 process . exit ( 1 ) ;
356356 }
357357
@@ -395,24 +395,36 @@ class SessionManager {
395395
396396function createClientInfo ( packageLocation : string ) : ClientInfo {
397397 const packageJSON = require ( packageLocation ) ;
398- const installationDir = process . env . PLAYWRIGHT_CLI_INSTALLATION_FOR_TEST || packageLocation ;
398+ const workspaceDir = findWorkspaceDir ( process . cwd ( ) ) || packageLocation ;
399399 const version = process . env . PLAYWRIGHT_CLI_VERSION_FOR_TEST || packageJSON . version ;
400400
401401 const hash = crypto . createHash ( 'sha1' ) ;
402- hash . update ( installationDir ) ;
403- const installationDirHash = hash . digest ( 'hex' ) . substring ( 0 , 16 ) ;
402+ hash . update ( workspaceDir ) ;
403+ const workspaceDirHash = hash . digest ( 'hex' ) . substring ( 0 , 16 ) ;
404404
405405 return {
406406 version,
407- installationDir,
408- installationDirHash,
409- daemonProfilesDir : daemonProfilesDir ( installationDirHash ) ,
407+ workspaceDirHash,
408+ daemonProfilesDir : daemonProfilesDir ( workspaceDirHash ) ,
410409 } ;
411410}
412411
413- const daemonProfilesDir = ( installationDirHash : string ) => {
412+ function findWorkspaceDir ( startDir : string ) : string | undefined {
413+ let dir = startDir ;
414+ for ( let i = 0 ; i < 10 ; i ++ ) {
415+ if ( fs . existsSync ( path . join ( dir , '.playwright' ) ) )
416+ return dir ;
417+ const parentDir = path . dirname ( dir ) ;
418+ if ( parentDir === dir )
419+ break ;
420+ dir = parentDir ;
421+ }
422+ return undefined ;
423+ }
424+
425+ const daemonProfilesDir = ( workspaceDirHash : string ) => {
414426 if ( process . env . PLAYWRIGHT_DAEMON_SESSION_DIR )
415- return process . env . PLAYWRIGHT_DAEMON_SESSION_DIR ;
427+ return path . join ( process . env . PLAYWRIGHT_DAEMON_SESSION_DIR , workspaceDirHash ) ;
416428
417429 let localCacheDir : string | undefined ;
418430 if ( process . platform === 'linux' )
@@ -423,7 +435,7 @@ const daemonProfilesDir = (installationDirHash: string) => {
423435 localCacheDir = process . env . LOCALAPPDATA || path . join ( os . homedir ( ) , 'AppData' , 'Local' ) ;
424436 if ( ! localCacheDir )
425437 throw new Error ( 'Unsupported platform: ' + process . platform ) ;
426- return path . join ( localCacheDir , 'ms-playwright' , 'daemon' , installationDirHash ) ;
438+ return path . join ( localCacheDir , 'ms-playwright' , 'daemon' , workspaceDirHash ) ;
427439} ;
428440
429441type GlobalOptions = {
@@ -510,6 +522,8 @@ export async function program(packageLocation: string) {
510522 } else {
511523 const restartMarker = ! session . isCompatible ( ) ? ` - v${ session . config ( ) . version } , please reopen` : '' ;
512524 console . log ( ` ${ session . name } ${ restartMarker } ` ) ;
525+ const config = session . config ( ) ;
526+ configToFormattedArgs ( config . cli ) . forEach ( arg => console . log ( ` ${ arg } ` ) ) ;
513527 }
514528 }
515529 if ( sessions . size === 0 )
@@ -525,7 +539,7 @@ export async function program(packageLocation: string) {
525539 case 'delete-data' :
526540 await sessionManager . deleteData ( args as GlobalOptions ) ;
527541 return ;
528- case 'kill-all' :
542+ case 'session- kill-all' :
529543 await killAllDaemons ( ) ;
530544 return ;
531545 case 'open' :
@@ -534,40 +548,49 @@ export async function program(packageLocation: string) {
534548 case 'close' :
535549 await sessionManager . close ( args as GlobalOptions ) ;
536550 return ;
537- case 'install-skills ' :
538- await installSkills ( ) ;
551+ case 'install' :
552+ await install ( args ) ;
539553 return ;
540554 default :
541555 await sessionManager . run ( args ) ;
542556 }
543557}
544558
545- async function installSkills ( ) {
546- const skillSourceDir = path . join ( __dirname , '../../skill' ) ;
547- const skillDestDir = path . join ( process . cwd ( ) , '.claude' , 'skills' , 'playwright-cli' ) ;
559+ async function install ( args : MinimistArgs ) {
560+ const cwd = process . cwd ( ) ;
548561
549- if ( ! fs . existsSync ( skillSourceDir ) ) {
550- console . error ( 'Skills source directory not found:' , skillSourceDir ) ;
551- process . exit ( 1 ) ;
552- }
562+ // Create .playwright folder to mark workspace root
563+ const playwrightDir = path . join ( cwd , '.playwright' ) ;
564+ await fs . promises . mkdir ( playwrightDir , { recursive : true } ) ;
565+ console . log ( `Workspace initialized at ${ cwd } ` ) ;
566+
567+ if ( args . skills ) {
568+ const skillSourceDir = path . join ( __dirname , '../../skill' ) ;
569+ const skillDestDir = path . join ( cwd , '.claude' , 'skills' , 'playwright-cli' ) ;
553570
554- await fs . promises . cp ( skillSourceDir , skillDestDir , { recursive : true } ) ;
555- console . log ( `Skills installed to ${ path . relative ( process . cwd ( ) , skillDestDir ) } ` ) ;
571+ if ( ! fs . existsSync ( skillSourceDir ) ) {
572+ console . error ( 'Skills source directory not found:' , skillSourceDir ) ;
573+ process . exit ( 1 ) ;
574+ }
575+
576+ await fs . promises . cp ( skillSourceDir , skillDestDir , { recursive : true } ) ;
577+ console . log ( `Skills installed to ${ path . relative ( cwd , skillDestDir ) } ` ) ;
578+ }
556579}
557580
558581function daemonSocketPath ( clientInfo : ClientInfo , sessionName : string ) : string {
559582 const socketName = `${ sessionName } .sock` ;
560583 if ( os . platform ( ) === 'win32' )
561- return `\\\\.\\pipe\\${ clientInfo . installationDirHash } -${ socketName } ` ;
584+ return `\\\\.\\pipe\\${ clientInfo . workspaceDirHash } -${ socketName } ` ;
562585 const socketsDir = process . env . PLAYWRIGHT_DAEMON_SOCKETS_DIR || path . join ( os . tmpdir ( ) , 'playwright-cli' ) ;
563- return path . join ( socketsDir , clientInfo . installationDirHash , socketName ) ;
586+ return path . join ( socketsDir , clientInfo . workspaceDirHash , socketName ) ;
564587}
565588
566589function sessionConfigFromArgs ( clientInfo : ClientInfo , sessionName : string , args : MinimistArgs ) : SessionConfig {
567590 let config = args . config ? path . resolve ( args . config ) : undefined ;
568591 try {
569- if ( ! config && fs . existsSync ( ' playwright- cli.json') )
570- config = path . resolve ( 'playwright- cli.json' ) ;
592+ if ( ! config && fs . existsSync ( path . join ( '. playwright' , ' cli.config. json') ) )
593+ config = path . resolve ( '. playwright' , ' cli.config .json') ;
571594 } catch {
572595 }
573596
0 commit comments