Skip to content

Commit b962bdd

Browse files
committed
Add start URL browser flags
1 parent 8d26914 commit b962bdd

7 files changed

Lines changed: 148 additions & 9 deletions

File tree

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,7 @@ Commands with JSON output support:
208208
- `-s, --stealth` - Launch browser in stealth mode to avoid detection
209209
- `-H, --headless` - Launch browser without GUI access
210210
- `--kiosk` - Launch browser in kiosk mode
211+
- `--start-url <url>` - Initial page to open on launch
211212
- `--pool-id <id>` - Acquire a browser from the specified pool (mutually exclusive with --pool-name; ignores other session flags)
212213
- `--pool-name <name>` - Acquire a browser from the pool name (mutually exclusive with --pool-id; ignores other session flags)
213214
- `--output json`, `-o json` - Output raw JSON object
@@ -242,7 +243,7 @@ Commands with JSON output support:
242243
- `--fill-rate <n>` - Percentage of the pool to fill per minute
243244
- `--timeout <seconds>` - Idle timeout for browsers acquired from the pool
244245
- `--stealth`, `--headless`, `--kiosk` - Default pool configuration
245-
- `--profile-id`, `--profile-name`, `--save-changes`, `--proxy-id`, `--extension`, `--viewport` - Same semantics as `kernel browsers create`
246+
- `--profile-id`, `--profile-name`, `--save-changes`, `--proxy-id`, `--start-url`, `--extension`, `--viewport` - Same semantics as `kernel browsers create`
246247
- `--output json`, `-o json` - Output raw JSON object
247248
- `kernel browser-pools get <id-or-name>` - Get pool details
248249
- `--output json`, `-o json` - Output raw JSON object

cmd/browser_pools.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ type BrowserPoolsCreateInput struct {
8686
ProfileName string
8787
ProfileSaveChanges BoolFlag
8888
ProxyID string
89+
StartURL string
8990
Extensions []string
9091
Viewport string
9192
Output string
@@ -131,6 +132,9 @@ func (c BrowserPoolsCmd) Create(ctx context.Context, in BrowserPoolsCreateInput)
131132
if in.ProxyID != "" {
132133
params.ProxyID = kernel.String(in.ProxyID)
133134
}
135+
if in.StartURL != "" {
136+
params.StartURL = kernel.String(in.StartURL)
137+
}
134138

135139
params.Extensions = buildExtensionsParam(in.Extensions)
136140

@@ -196,6 +200,7 @@ func (c BrowserPoolsCmd) Get(ctx context.Context, in BrowserPoolsGetInput) error
196200
{"Kiosk Mode", fmt.Sprintf("%t", cfg.KioskMode)},
197201
{"Profile", formatProfile(cfg.Profile)},
198202
{"Proxy ID", util.OrDash(cfg.ProxyID)},
203+
{"Start URL", util.OrDash(cfg.StartURL)},
199204
{"Extensions", formatExtensions(cfg.Extensions)},
200205
{"Viewport", formatViewport(cfg.Viewport)},
201206
}
@@ -217,6 +222,7 @@ type BrowserPoolsUpdateInput struct {
217222
ProfileName string
218223
ProfileSaveChanges BoolFlag
219224
ProxyID string
225+
StartURL string
220226
Extensions []string
221227
Viewport string
222228
DiscardAllIdle BoolFlag
@@ -267,6 +273,9 @@ func (c BrowserPoolsCmd) Update(ctx context.Context, in BrowserPoolsUpdateInput)
267273
if in.ProxyID != "" {
268274
params.ProxyID = kernel.String(in.ProxyID)
269275
}
276+
if in.StartURL != "" {
277+
params.StartURL = kernel.String(in.StartURL)
278+
}
270279

271280
params.Extensions = buildExtensionsParam(in.Extensions)
272281

@@ -352,6 +361,9 @@ func (c BrowserPoolsCmd) Acquire(ctx context.Context, in BrowserPoolsAcquireInpu
352361
{"CDP WebSocket URL", resp.CdpWsURL},
353362
{"Live View URL", resp.BrowserLiveViewURL},
354363
}
364+
if resp.StartURL != "" {
365+
tableData = append(tableData, []string{"Start URL", resp.StartURL})
366+
}
355367
PrintTableNoPad(tableData, true)
356368
return nil
357369
}
@@ -472,6 +484,7 @@ func init() {
472484
browserPoolsCreateCmd.Flags().String("profile-name", "", "Profile name")
473485
browserPoolsCreateCmd.Flags().Bool("save-changes", false, "Save changes to profile")
474486
browserPoolsCreateCmd.Flags().String("proxy-id", "", "Proxy ID")
487+
browserPoolsCreateCmd.Flags().String("start-url", "", "Initial page to open for new browsers")
475488
browserPoolsCreateCmd.Flags().StringSlice("extension", []string{}, "Extension IDs or names")
476489
browserPoolsCreateCmd.Flags().String("viewport", "", "Viewport size (e.g. 1280x800)")
477490

@@ -488,6 +501,7 @@ func init() {
488501
browserPoolsUpdateCmd.Flags().String("profile-name", "", "Profile name")
489502
browserPoolsUpdateCmd.Flags().Bool("save-changes", false, "Save changes to profile")
490503
browserPoolsUpdateCmd.Flags().String("proxy-id", "", "Proxy ID")
504+
browserPoolsUpdateCmd.Flags().String("start-url", "", "Initial page to open for new browsers")
491505
browserPoolsUpdateCmd.Flags().StringSlice("extension", []string{}, "Extension IDs or names")
492506
browserPoolsUpdateCmd.Flags().String("viewport", "", "Viewport size (e.g. 1280x800)")
493507
browserPoolsUpdateCmd.Flags().Bool("discard-all-idle", false, "Discard all idle browsers")
@@ -539,6 +553,7 @@ func runBrowserPoolsCreate(cmd *cobra.Command, args []string) error {
539553
profileName, _ := cmd.Flags().GetString("profile-name")
540554
saveChanges, _ := cmd.Flags().GetBool("save-changes")
541555
proxyID, _ := cmd.Flags().GetString("proxy-id")
556+
startURL, _ := cmd.Flags().GetString("start-url")
542557
extensions, _ := cmd.Flags().GetStringSlice("extension")
543558
viewport, _ := cmd.Flags().GetString("viewport")
544559
output, _ := cmd.Flags().GetString("output")
@@ -555,6 +570,7 @@ func runBrowserPoolsCreate(cmd *cobra.Command, args []string) error {
555570
ProfileName: profileName,
556571
ProfileSaveChanges: BoolFlag{Set: cmd.Flags().Changed("save-changes"), Value: saveChanges},
557572
ProxyID: proxyID,
573+
StartURL: startURL,
558574
Extensions: extensions,
559575
Viewport: viewport,
560576
Output: output,
@@ -585,6 +601,7 @@ func runBrowserPoolsUpdate(cmd *cobra.Command, args []string) error {
585601
profileName, _ := cmd.Flags().GetString("profile-name")
586602
saveChanges, _ := cmd.Flags().GetBool("save-changes")
587603
proxyID, _ := cmd.Flags().GetString("proxy-id")
604+
startURL, _ := cmd.Flags().GetString("start-url")
588605
extensions, _ := cmd.Flags().GetStringSlice("extension")
589606
viewport, _ := cmd.Flags().GetString("viewport")
590607
discardIdle, _ := cmd.Flags().GetBool("discard-all-idle")
@@ -603,6 +620,7 @@ func runBrowserPoolsUpdate(cmd *cobra.Command, args []string) error {
603620
ProfileName: profileName,
604621
ProfileSaveChanges: BoolFlag{Set: cmd.Flags().Changed("save-changes"), Value: saveChanges},
605622
ProxyID: proxyID,
623+
StartURL: startURL,
606624
Extensions: extensions,
607625
Viewport: viewport,
608626
DiscardAllIdle: BoolFlag{Set: cmd.Flags().Changed("discard-all-idle"), Value: discardIdle},

cmd/browser_pools_test.go

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
package cmd
2+
3+
import (
4+
"context"
5+
"testing"
6+
7+
"github.com/kernel/kernel-go-sdk"
8+
"github.com/kernel/kernel-go-sdk/option"
9+
"github.com/stretchr/testify/assert"
10+
)
11+
12+
type fakeBrowserPoolsService struct {
13+
newFunc func(ctx context.Context, body kernel.BrowserPoolNewParams, opts ...option.RequestOption) (*kernel.BrowserPool, error)
14+
updateFunc func(ctx context.Context, id string, body kernel.BrowserPoolUpdateParams, opts ...option.RequestOption) (*kernel.BrowserPool, error)
15+
}
16+
17+
func (f *fakeBrowserPoolsService) List(ctx context.Context, opts ...option.RequestOption) (*[]kernel.BrowserPool, error) {
18+
return &[]kernel.BrowserPool{}, nil
19+
}
20+
21+
func (f *fakeBrowserPoolsService) New(ctx context.Context, body kernel.BrowserPoolNewParams, opts ...option.RequestOption) (*kernel.BrowserPool, error) {
22+
if f.newFunc != nil {
23+
return f.newFunc(ctx, body, opts...)
24+
}
25+
return &kernel.BrowserPool{ID: "pool123"}, nil
26+
}
27+
28+
func (f *fakeBrowserPoolsService) Get(ctx context.Context, id string, opts ...option.RequestOption) (*kernel.BrowserPool, error) {
29+
return &kernel.BrowserPool{ID: id}, nil
30+
}
31+
32+
func (f *fakeBrowserPoolsService) Update(ctx context.Context, id string, body kernel.BrowserPoolUpdateParams, opts ...option.RequestOption) (*kernel.BrowserPool, error) {
33+
if f.updateFunc != nil {
34+
return f.updateFunc(ctx, id, body, opts...)
35+
}
36+
return &kernel.BrowserPool{ID: id}, nil
37+
}
38+
39+
func (f *fakeBrowserPoolsService) Delete(ctx context.Context, id string, body kernel.BrowserPoolDeleteParams, opts ...option.RequestOption) error {
40+
return nil
41+
}
42+
43+
func (f *fakeBrowserPoolsService) Acquire(ctx context.Context, id string, body kernel.BrowserPoolAcquireParams, opts ...option.RequestOption) (*kernel.BrowserPoolAcquireResponse, error) {
44+
return &kernel.BrowserPoolAcquireResponse{}, nil
45+
}
46+
47+
func (f *fakeBrowserPoolsService) Release(ctx context.Context, id string, body kernel.BrowserPoolReleaseParams, opts ...option.RequestOption) error {
48+
return nil
49+
}
50+
51+
func (f *fakeBrowserPoolsService) Flush(ctx context.Context, id string, opts ...option.RequestOption) error {
52+
return nil
53+
}
54+
55+
func TestBrowserPoolsCreate_WithStartURL(t *testing.T) {
56+
setupStdoutCapture(t)
57+
var captured kernel.BrowserPoolNewParams
58+
fake := &fakeBrowserPoolsService{newFunc: func(ctx context.Context, body kernel.BrowserPoolNewParams, opts ...option.RequestOption) (*kernel.BrowserPool, error) {
59+
captured = body
60+
return &kernel.BrowserPool{ID: "pool123"}, nil
61+
}}
62+
c := BrowserPoolsCmd{client: fake}
63+
64+
err := c.Create(context.Background(), BrowserPoolsCreateInput{
65+
Size: 1,
66+
StartURL: "https://example.com",
67+
})
68+
69+
assert.NoError(t, err)
70+
assert.True(t, captured.StartURL.Valid())
71+
assert.Equal(t, "https://example.com", captured.StartURL.Value)
72+
}
73+
74+
func TestBrowserPoolsUpdate_WithStartURL(t *testing.T) {
75+
setupStdoutCapture(t)
76+
var captured kernel.BrowserPoolUpdateParams
77+
fake := &fakeBrowserPoolsService{updateFunc: func(ctx context.Context, id string, body kernel.BrowserPoolUpdateParams, opts ...option.RequestOption) (*kernel.BrowserPool, error) {
78+
captured = body
79+
return &kernel.BrowserPool{ID: id}, nil
80+
}}
81+
c := BrowserPoolsCmd{client: fake}
82+
83+
err := c.Update(context.Background(), BrowserPoolsUpdateInput{
84+
IDOrName: "pool123",
85+
StartURL: "https://example.com",
86+
})
87+
88+
assert.NoError(t, err)
89+
assert.True(t, captured.StartURL.Valid())
90+
assert.Equal(t, "https://example.com", captured.StartURL.Value)
91+
}

cmd/browsers.go

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,7 @@ type BrowsersCreateInput struct {
186186
ProfileName string
187187
ProfileSaveChanges BoolFlag
188188
ProxyID string
189+
StartURL string
189190
Extensions []string
190191
Viewport string
191192
Output string
@@ -392,6 +393,9 @@ func (b BrowsersCmd) Create(ctx context.Context, in BrowsersCreateInput) error {
392393
if in.ProxyID != "" {
393394
params.ProxyID = kernel.Opt(in.ProxyID)
394395
}
396+
if in.StartURL != "" {
397+
params.StartURL = kernel.Opt(in.StartURL)
398+
}
395399

396400
// Map extensions (IDs or names) into params.Extensions
397401
if len(in.Extensions) > 0 {
@@ -435,17 +439,17 @@ func (b BrowsersCmd) Create(ctx context.Context, in BrowsersCreateInput) error {
435439
return util.PrintPrettyJSON(browser)
436440
}
437441

438-
printBrowserSessionResult(browser.SessionID, browser.CdpWsURL, browser.BrowserLiveViewURL, browser.Persistence, browser.Profile)
442+
printBrowserSessionResult(browser.SessionID, browser.CdpWsURL, browser.BrowserLiveViewURL, browser.Persistence, browser.Profile, browser.StartURL)
439443
return nil
440444
}
441445

442-
func printBrowserSessionResult(sessionID, cdpURL, liveViewURL string, persistence kernel.BrowserPersistence, profile kernel.Profile) {
443-
tableData := buildBrowserTableData(sessionID, cdpURL, liveViewURL, persistence, profile)
446+
func printBrowserSessionResult(sessionID, cdpURL, liveViewURL string, persistence kernel.BrowserPersistence, profile kernel.Profile, startURL string) {
447+
tableData := buildBrowserTableData(sessionID, cdpURL, liveViewURL, persistence, profile, startURL)
444448
PrintTableNoPad(tableData, true)
445449
}
446450

447451
// buildBrowserTableData creates a base table with common browser session fields.
448-
func buildBrowserTableData(sessionID, cdpURL, liveViewURL string, persistence kernel.BrowserPersistence, profile kernel.Profile) pterm.TableData {
452+
func buildBrowserTableData(sessionID, cdpURL, liveViewURL string, persistence kernel.BrowserPersistence, profile kernel.Profile, startURL string) pterm.TableData {
449453
tableData := pterm.TableData{
450454
{"Property", "Value"},
451455
{"Session ID", sessionID},
@@ -464,6 +468,9 @@ func buildBrowserTableData(sessionID, cdpURL, liveViewURL string, persistence ke
464468
}
465469
tableData = append(tableData, []string{"Profile", profVal})
466470
}
471+
if startURL != "" {
472+
tableData = append(tableData, []string{"Start URL", startURL})
473+
}
467474
return tableData
468475
}
469476

@@ -554,6 +561,7 @@ func (b BrowsersCmd) Get(ctx context.Context, in BrowsersGetInput) error {
554561
browser.BrowserLiveViewURL,
555562
browser.Persistence,
556563
browser.Profile,
564+
browser.StartURL,
557565
)
558566

559567
// Append additional detailed fields
@@ -2525,6 +2533,7 @@ func init() {
25252533
browsersCreateCmd.Flags().String("profile-name", "", "Profile name to load into the browser session (mutually exclusive with --profile-id)")
25262534
browsersCreateCmd.Flags().Bool("save-changes", false, "If set, save changes back to the profile when the session ends")
25272535
browsersCreateCmd.Flags().String("proxy-id", "", "Proxy ID to use for the browser session")
2536+
browsersCreateCmd.Flags().String("start-url", "", "Initial page to open on launch")
25282537
browsersCreateCmd.Flags().StringSlice("extension", []string{}, "Extension IDs or names to load (repeatable; may be passed multiple times or comma-separated)")
25292538
browsersCreateCmd.Flags().String("viewport", "", "Browser viewport size (e.g., 1920x1080@25). Supported: 2560x1440@10, 1920x1080@25, 1920x1200@25, 1440x900@25, 1024x768@60, 1200x800@60, 1280x800@60")
25302539
browsersCreateCmd.Flags().Bool("viewport-interactive", false, "Interactively select viewport size from list")
@@ -2597,6 +2606,7 @@ func runBrowsersCreate(cmd *cobra.Command, args []string) error {
25972606
profileName, _ := cmd.Flags().GetString("profile-name")
25982607
saveChanges, _ := cmd.Flags().GetBool("save-changes")
25992608
proxyID, _ := cmd.Flags().GetString("proxy-id")
2609+
startURL, _ := cmd.Flags().GetString("start-url")
26002610
extensions, _ := cmd.Flags().GetStringSlice("extension")
26012611
viewport, _ := cmd.Flags().GetString("viewport")
26022612
viewportInteractive, _ := cmd.Flags().GetBool("viewport-interactive")
@@ -2676,7 +2686,7 @@ func runBrowsersCreate(cmd *cobra.Command, args []string) error {
26762686
if output == "json" {
26772687
return util.PrintPrettyJSON(resp)
26782688
}
2679-
printBrowserSessionResult(resp.SessionID, resp.CdpWsURL, resp.BrowserLiveViewURL, resp.Persistence, resp.Profile)
2689+
printBrowserSessionResult(resp.SessionID, resp.CdpWsURL, resp.BrowserLiveViewURL, resp.Persistence, resp.Profile, resp.StartURL)
26802690
return nil
26812691
}
26822692

@@ -2709,6 +2719,7 @@ func runBrowsersCreate(cmd *cobra.Command, args []string) error {
27092719
ProfileName: profileName,
27102720
ProfileSaveChanges: BoolFlag{Set: cmd.Flags().Changed("save-changes"), Value: saveChanges},
27112721
ProxyID: proxyID,
2722+
StartURL: startURL,
27122723
Extensions: extensions,
27132724
Viewport: viewport,
27142725
Output: output,

cmd/browsers_test.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1632,6 +1632,24 @@ func TestBrowsersCreate_WithViewportNoRefreshRate(t *testing.T) {
16321632
assert.False(t, captured.Viewport.RefreshRate.Valid())
16331633
}
16341634

1635+
func TestBrowsersCreate_WithStartURL(t *testing.T) {
1636+
setupStdoutCapture(t)
1637+
var captured kernel.BrowserNewParams
1638+
fake := &FakeBrowsersService{NewFunc: func(ctx context.Context, body kernel.BrowserNewParams, opts ...option.RequestOption) (*kernel.BrowserNewResponse, error) {
1639+
captured = body
1640+
return &kernel.BrowserNewResponse{SessionID: "session123", CdpWsURL: "ws://example"}, nil
1641+
}}
1642+
b := BrowsersCmd{browsers: fake}
1643+
1644+
err := b.Create(context.Background(), BrowsersCreateInput{
1645+
StartURL: "https://example.com",
1646+
})
1647+
1648+
assert.NoError(t, err)
1649+
assert.True(t, captured.StartURL.Valid())
1650+
assert.Equal(t, "https://example.com", captured.StartURL.Value)
1651+
}
1652+
16351653
func TestBrowsersCreate_WithInvalidViewport(t *testing.T) {
16361654
setupStdoutCapture(t)
16371655
fake := &FakeBrowsersService{}

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ require (
99
github.com/charmbracelet/lipgloss/v2 v2.0.0-beta.1
1010
github.com/golang-jwt/jwt/v5 v5.2.2
1111
github.com/joho/godotenv v1.5.1
12-
github.com/kernel/kernel-go-sdk v0.52.0
12+
github.com/kernel/kernel-go-sdk v0.53.0
1313
github.com/klauspost/compress v1.18.5
1414
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c
1515
github.com/pterm/pterm v0.12.80

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,8 @@ github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2
6464
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
6565
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
6666
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
67-
github.com/kernel/kernel-go-sdk v0.52.0 h1:ChRAMo6oMAEmazC610FtcqKFO/cqHzU9v1ECF0MiR8E=
68-
github.com/kernel/kernel-go-sdk v0.52.0/go.mod h1:EeZzSuHZVeHKxKCPUzxou2bovNGhXaz0RXrSqKNf1AQ=
67+
github.com/kernel/kernel-go-sdk v0.53.0 h1:XgcuJv3G4a6nr9LYBZ21gLUWvsIDLSG4YhZAngNrqE0=
68+
github.com/kernel/kernel-go-sdk v0.53.0/go.mod h1:EeZzSuHZVeHKxKCPUzxou2bovNGhXaz0RXrSqKNf1AQ=
6969
github.com/klauspost/compress v1.18.5 h1:/h1gH5Ce+VWNLSWqPzOVn6XBO+vJbCNGvjoaGBFW2IE=
7070
github.com/klauspost/compress v1.18.5/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ=
7171
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=

0 commit comments

Comments
 (0)