@@ -73,6 +73,11 @@ type BrowserLogService interface {
7373 StreamStreaming (ctx context.Context , id string , query kernel.BrowserLogStreamParams , opts ... option.RequestOption ) (stream * ssestream.Stream [shared.LogEvent ])
7474}
7575
76+ // BrowserPlaywrightService defines the subset we use for Playwright execution.
77+ type BrowserPlaywrightService interface {
78+ Execute (ctx context.Context , id string , body kernel.BrowserPlaywrightExecuteParams , opts ... option.RequestOption ) (res * kernel.BrowserPlaywrightExecuteResponse , err error )
79+ }
80+
7681// BrowserComputerService defines the subset we use for OS-level mouse & screen.
7782type BrowserComputerService interface {
7883 CaptureScreenshot (ctx context.Context , id string , body kernel.BrowserComputerCaptureScreenshotParams , opts ... option.RequestOption ) (res * http.Response , err error )
@@ -166,12 +171,13 @@ type BrowsersViewInput struct {
166171
167172// BrowsersCmd is a cobra-independent command handler for browsers operations.
168173type BrowsersCmd struct {
169- browsers BrowsersService
170- replays BrowserReplaysService
171- fs BrowserFSService
172- process BrowserProcessService
173- logs BrowserLogService
174- computer BrowserComputerService
174+ browsers BrowsersService
175+ replays BrowserReplaysService
176+ fs BrowserFSService
177+ process BrowserProcessService
178+ logs BrowserLogService
179+ computer BrowserComputerService
180+ playwright BrowserPlaywrightService
175181}
176182
177183type BrowsersListInput struct {
@@ -940,6 +946,59 @@ type BrowsersProcessStdoutStreamInput struct {
940946 ProcessID string
941947}
942948
949+ // Playwright
950+ type BrowsersPlaywrightExecuteInput struct {
951+ Identifier string
952+ Code string
953+ Timeout int64
954+ }
955+
956+ func (b BrowsersCmd ) PlaywrightExecute (ctx context.Context , in BrowsersPlaywrightExecuteInput ) error {
957+ if b .playwright == nil {
958+ pterm .Error .Println ("playwright service not available" )
959+ return nil
960+ }
961+ br , err := b .resolveBrowserByIdentifier (ctx , in .Identifier )
962+ if err != nil {
963+ return util.CleanedUpSdkError {Err : err }
964+ }
965+ if br == nil {
966+ pterm .Error .Printf ("Browser '%s' not found\n " , in .Identifier )
967+ return nil
968+ }
969+ params := kernel.BrowserPlaywrightExecuteParams {Code : in .Code }
970+ if in .Timeout > 0 {
971+ params .TimeoutSec = kernel .Opt (in .Timeout )
972+ }
973+ res , err := b .playwright .Execute (ctx , br .SessionID , params )
974+ if err != nil {
975+ return util.CleanedUpSdkError {Err : err }
976+ }
977+
978+ rows := pterm.TableData {{"Property" , "Value" }, {"Success" , fmt .Sprintf ("%t" , res .Success )}}
979+ PrintTableNoPad (rows , true )
980+
981+ if res .Stdout != "" {
982+ pterm .Info .Println ("stdout:" )
983+ fmt .Println (res .Stdout )
984+ }
985+ if res .Stderr != "" {
986+ pterm .Info .Println ("stderr:" )
987+ fmt .Fprintln (os .Stderr , res .Stderr )
988+ }
989+ if res .Result != nil {
990+ bs , err := json .MarshalIndent (res .Result , "" , " " )
991+ if err == nil {
992+ pterm .Info .Println ("result:" )
993+ fmt .Println (string (bs ))
994+ }
995+ }
996+ if ! res .Success && res .Error != "" {
997+ pterm .Error .Printf ("error: %s\n " , res .Error )
998+ }
999+ return nil
1000+ }
1001+
9431002func (b BrowsersCmd ) ProcessExec (ctx context.Context , in BrowsersProcessExecInput ) error {
9441003 if b .process == nil {
9451004 pterm .Error .Println ("process service not available" )
@@ -1898,6 +1957,13 @@ func init() {
18981957 computerRoot .AddCommand (computerClick , computerMove , computerScreenshot , computerType , computerPressKey , computerScroll , computerDrag )
18991958 browsersCmd .AddCommand (computerRoot )
19001959
1960+ // playwright
1961+ playwrightRoot := & cobra.Command {Use : "playwright" , Short : "Playwright operations" }
1962+ playwrightExecute := & cobra.Command {Use : "execute <id|persistent-id> [code]" , Short : "Execute Playwright/TypeScript code against the browser" , Args : cobra .MinimumNArgs (1 ), RunE : runBrowsersPlaywrightExecute }
1963+ playwrightExecute .Flags ().Int64 ("timeout" , 0 , "Maximum execution time in seconds (default per server)" )
1964+ playwrightRoot .AddCommand (playwrightExecute )
1965+ browsersCmd .AddCommand (playwrightRoot )
1966+
19011967 // Add flags for create command
19021968 browsersCreateCmd .Flags ().StringP ("persistent-id" , "p" , "" , "Unique identifier for browser session persistence" )
19031969 browsersCreateCmd .Flags ().BoolP ("stealth" , "s" , false , "Launch browser in stealth mode to avoid detection" )
@@ -2120,6 +2186,32 @@ func runBrowsersProcessStdoutStream(cmd *cobra.Command, args []string) error {
21202186 return b .ProcessStdoutStream (cmd .Context (), BrowsersProcessStdoutStreamInput {Identifier : args [0 ], ProcessID : args [1 ]})
21212187}
21222188
2189+ func runBrowsersPlaywrightExecute (cmd * cobra.Command , args []string ) error {
2190+ client := getKernelClient (cmd )
2191+ svc := client .Browsers
2192+
2193+ var code string
2194+ if len (args ) >= 2 {
2195+ code = strings .Join (args [1 :], " " )
2196+ } else {
2197+ // Read code from stdin
2198+ stat , _ := os .Stdin .Stat ()
2199+ if (stat .Mode () & os .ModeCharDevice ) != 0 {
2200+ pterm .Error .Println ("no code provided. Provide code as an argument or pipe via stdin" )
2201+ return nil
2202+ }
2203+ data , err := io .ReadAll (os .Stdin )
2204+ if err != nil {
2205+ pterm .Error .Printf ("failed to read stdin: %v\n " , err )
2206+ return nil
2207+ }
2208+ code = string (data )
2209+ }
2210+ timeout , _ := cmd .Flags ().GetInt64 ("timeout" )
2211+ b := BrowsersCmd {browsers : & svc , playwright : & svc .Playwright }
2212+ return b .PlaywrightExecute (cmd .Context (), BrowsersPlaywrightExecuteInput {Identifier : args [0 ], Code : strings .TrimSpace (code ), Timeout : timeout })
2213+ }
2214+
21232215func runBrowsersFSNewDirectory (cmd * cobra.Command , args []string ) error {
21242216 client := getKernelClient (cmd )
21252217 svc := client .Browsers
0 commit comments