Skip to content

Commit d187a2d

Browse files
IlyaasKclaude
andcommitted
Adopt kernel-go-sdk v0.72.0; add extensions get + telemetry events; drop pool save_changes
- Bump kernel-go-sdk to v0.72.0. Adapts APIKeyService.Get (now takes APIKeyGetParams) and the browser-pool profile change in kernel/kernel#2484. - New `extensions get <id-or-name>`; new `browsers telemetry events <id>` (paged historical read with X-Next-Offset); new `--replay` on `browsers telemetry stream` (mutually exclusive with --seq). - Browser pools now have their own profile type (BrowserPoolProfile, id/name only, no save_changes; kernel/kernel#2484): drop `--save-changes` from `browser-pools create`/`update`, replace buildProfileParam with resolvePoolProfile (id/name selection, same validation), and drop the save-changes line from the pool profile display. Single-session `browsers create` keeps `--save-changes` (unchanged). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent d52581b commit d187a2d

12 files changed

Lines changed: 360 additions & 122 deletions

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -263,7 +263,7 @@ Commands with JSON output support:
263263
- `--fill-rate <n>` - Percentage of the pool to fill per minute
264264
- `--timeout <seconds>` - Idle timeout for browsers acquired from the pool
265265
- `--stealth`, `--headless`, `--kiosk` - Default pool configuration
266-
- `--profile-id`, `--profile-name`, `--save-changes`, `--proxy-id`, `--start-url`, `--extension`, `--viewport` - Same semantics as `kernel browsers create`
266+
- `--profile-id`, `--profile-name`, `--proxy-id`, `--start-url`, `--extension`, `--viewport` - Same semantics as `kernel browsers create`
267267
- `--chrome-policy <json>` / `--chrome-policy-file <path>` - Custom Chrome enterprise policy applied to every browser in the pool, as a JSON object or from a file (`-` for stdin). Same semantics as `kernel browsers create`.
268268
- `--output json`, `-o json` - Output raw JSON object
269269
- `kernel browser-pools get <id-or-name>` - Get pool details

cmd/api_keys.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import (
1414

1515
type APIKeysService interface {
1616
New(ctx context.Context, body kernel.APIKeyNewParams, opts ...option.RequestOption) (*kernel.CreatedAPIKey, error)
17-
Get(ctx context.Context, id string, opts ...option.RequestOption) (*kernel.APIKey, error)
17+
Get(ctx context.Context, id string, query kernel.APIKeyGetParams, opts ...option.RequestOption) (*kernel.APIKey, error)
1818
Update(ctx context.Context, id string, body kernel.APIKeyUpdateParams, opts ...option.RequestOption) (*kernel.APIKey, error)
1919
List(ctx context.Context, query kernel.APIKeyListParams, opts ...option.RequestOption) (*pagination.OffsetPagination[kernel.APIKey], error)
2020
Delete(ctx context.Context, id string, opts ...option.RequestOption) error
@@ -145,7 +145,7 @@ func (c APIKeysCmd) Get(ctx context.Context, in APIKeysGetInput) error {
145145
return err
146146
}
147147

148-
key, err := c.apiKeys.Get(ctx, in.ID)
148+
key, err := c.apiKeys.Get(ctx, in.ID, kernel.APIKeyGetParams{})
149149
if err != nil {
150150
return util.CleanedUpSdkError{Err: err}
151151
}

cmd/api_keys_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import (
1616

1717
type FakeAPIKeysService struct {
1818
NewFunc func(ctx context.Context, body kernel.APIKeyNewParams, opts ...option.RequestOption) (*kernel.CreatedAPIKey, error)
19-
GetFunc func(ctx context.Context, id string, opts ...option.RequestOption) (*kernel.APIKey, error)
19+
GetFunc func(ctx context.Context, id string, query kernel.APIKeyGetParams, opts ...option.RequestOption) (*kernel.APIKey, error)
2020
UpdateFunc func(ctx context.Context, id string, body kernel.APIKeyUpdateParams, opts ...option.RequestOption) (*kernel.APIKey, error)
2121
ListFunc func(ctx context.Context, query kernel.APIKeyListParams, opts ...option.RequestOption) (*pagination.OffsetPagination[kernel.APIKey], error)
2222
DeleteFunc func(ctx context.Context, id string, opts ...option.RequestOption) error
@@ -29,9 +29,9 @@ func (f *FakeAPIKeysService) New(ctx context.Context, body kernel.APIKeyNewParam
2929
return createdAPIKeyFromJSON(`{"id":"key_123","name":"default","key":"sk_test","masked_key":"sk_...test","created_at":"2026-05-27T12:00:00Z","created_by":{"id":"user_123","email":"dev@example.com","name":"Dev"},"expires_at":null,"project_id":null,"project_name":null}`), nil
3030
}
3131

32-
func (f *FakeAPIKeysService) Get(ctx context.Context, id string, opts ...option.RequestOption) (*kernel.APIKey, error) {
32+
func (f *FakeAPIKeysService) Get(ctx context.Context, id string, query kernel.APIKeyGetParams, opts ...option.RequestOption) (*kernel.APIKey, error) {
3333
if f.GetFunc != nil {
34-
return f.GetFunc(ctx, id, opts...)
34+
return f.GetFunc(ctx, id, query, opts...)
3535
}
3636
return apiKeyFromJSON(`{"id":"` + id + `","name":"default","masked_key":"sk_...test","created_at":"2026-05-27T12:00:00Z","created_by":{"id":"user_123","email":"dev@example.com","name":"Dev"},"expires_at":null,"project_id":null,"project_name":null}`), nil
3737
}
@@ -125,7 +125,7 @@ func TestAPIKeysRejectInvalidOutputBeforeCallingAPI(t *testing.T) {
125125
t.Fatal("New should not be called")
126126
return nil, nil
127127
},
128-
GetFunc: func(ctx context.Context, id string, opts ...option.RequestOption) (*kernel.APIKey, error) {
128+
GetFunc: func(ctx context.Context, id string, query kernel.APIKeyGetParams, opts ...option.RequestOption) (*kernel.APIKey, error) {
129129
t.Fatal("Get should not be called")
130130
return nil, nil
131131
},

cmd/browser_pools.go

Lines changed: 94 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -91,23 +91,22 @@ func (c BrowserPoolsCmd) List(ctx context.Context, in BrowserPoolsListInput) err
9191
}
9292

9393
type BrowserPoolsCreateInput struct {
94-
Name string
95-
Size int64
96-
FillRate int64
97-
TimeoutSeconds int64
98-
Stealth BoolFlag
99-
Headless BoolFlag
100-
Kiosk BoolFlag
101-
ProfileID string
102-
ProfileName string
103-
ProfileSaveChanges BoolFlag
104-
ProxyID string
105-
StartURL string
106-
Extensions []string
107-
Viewport string
108-
ChromePolicy string
109-
ChromePolicyFile string
110-
Output string
94+
Name string
95+
Size int64
96+
FillRate int64
97+
TimeoutSeconds int64
98+
Stealth BoolFlag
99+
Headless BoolFlag
100+
Kiosk BoolFlag
101+
ProfileID string
102+
ProfileName string
103+
ProxyID string
104+
StartURL string
105+
Extensions []string
106+
Viewport string
107+
ChromePolicy string
108+
ChromePolicyFile string
109+
Output string
111110
}
112111

113112
func (c BrowserPoolsCmd) Create(ctx context.Context, in BrowserPoolsCreateInput) error {
@@ -141,13 +140,17 @@ func (c BrowserPoolsCmd) Create(ctx context.Context, in BrowserPoolsCreateInput)
141140
params.KioskMode = kernel.Bool(in.Kiosk.Value)
142141
}
143142

144-
profile, err := buildProfileParam(in.ProfileID, in.ProfileName, in.ProfileSaveChanges)
143+
profileID, profileName, profileSet, err := resolvePoolProfile(in.ProfileID, in.ProfileName)
145144
if err != nil {
146145
pterm.Error.Println(err.Error())
147146
return nil
148147
}
149-
if profile != nil {
150-
params.Profile = *profile
148+
if profileSet {
149+
if profileID != "" {
150+
params.Profile.ID = kernel.String(profileID)
151+
} else {
152+
params.Profile.Name = kernel.String(profileName)
153+
}
151154
}
152155

153156
if in.ProxyID != "" {
@@ -239,26 +242,25 @@ func (c BrowserPoolsCmd) Get(ctx context.Context, in BrowserPoolsGetInput) error
239242
}
240243

241244
type BrowserPoolsUpdateInput struct {
242-
IDOrName string
243-
Name string
244-
Size int64
245-
FillRate int64
246-
TimeoutSeconds int64
247-
Stealth BoolFlag
248-
Headless BoolFlag
249-
Kiosk BoolFlag
250-
ProfileID string
251-
ProfileName string
252-
ProfileSaveChanges BoolFlag
253-
ProxyID string
254-
StartURL string
255-
ClearStartURL bool
256-
Extensions []string
257-
Viewport string
258-
ChromePolicy string
259-
ChromePolicyFile string
260-
DiscardAllIdle BoolFlag
261-
Output string
245+
IDOrName string
246+
Name string
247+
Size int64
248+
FillRate int64
249+
TimeoutSeconds int64
250+
Stealth BoolFlag
251+
Headless BoolFlag
252+
Kiosk BoolFlag
253+
ProfileID string
254+
ProfileName string
255+
ProxyID string
256+
StartURL string
257+
ClearStartURL bool
258+
Extensions []string
259+
Viewport string
260+
ChromePolicy string
261+
ChromePolicyFile string
262+
DiscardAllIdle BoolFlag
263+
Output string
262264
}
263265

264266
func (c BrowserPoolsCmd) Update(ctx context.Context, in BrowserPoolsUpdateInput) error {
@@ -299,13 +301,17 @@ func (c BrowserPoolsCmd) Update(ctx context.Context, in BrowserPoolsUpdateInput)
299301
params.DiscardAllIdle = kernel.Bool(in.DiscardAllIdle.Value)
300302
}
301303

302-
profile, err := buildProfileParam(in.ProfileID, in.ProfileName, in.ProfileSaveChanges)
304+
profileID, profileName, profileSet, err := resolvePoolProfile(in.ProfileID, in.ProfileName)
303305
if err != nil {
304306
pterm.Error.Println(err.Error())
305307
return nil
306308
}
307-
if profile != nil {
308-
params.Profile = *profile
309+
if profileSet {
310+
if profileID != "" {
311+
params.Profile.ID = kernel.String(profileID)
312+
} else {
313+
params.Profile.Name = kernel.String(profileName)
314+
}
309315
}
310316

311317
if in.ProxyID != "" {
@@ -561,7 +567,6 @@ func init() {
561567
browserPoolsCreateCmd.Flags().Bool("kiosk", false, "Enable kiosk mode")
562568
browserPoolsCreateCmd.Flags().String("profile-id", "", "Profile ID")
563569
browserPoolsCreateCmd.Flags().String("profile-name", "", "Profile name")
564-
browserPoolsCreateCmd.Flags().Bool("save-changes", false, "Save changes to profile")
565570
browserPoolsCreateCmd.Flags().String("proxy-id", "", "Proxy ID")
566571
browserPoolsCreateCmd.Flags().String("start-url", "", "Initial page to open for new browsers")
567572
browserPoolsCreateCmd.Flags().StringSlice("extension", []string{}, "Extension IDs or names")
@@ -581,7 +586,6 @@ func init() {
581586
browserPoolsUpdateCmd.Flags().Bool("kiosk", false, "Enable kiosk mode")
582587
browserPoolsUpdateCmd.Flags().String("profile-id", "", "Profile ID")
583588
browserPoolsUpdateCmd.Flags().String("profile-name", "", "Profile name")
584-
browserPoolsUpdateCmd.Flags().Bool("save-changes", false, "Save changes to profile")
585589
browserPoolsUpdateCmd.Flags().String("proxy-id", "", "Proxy ID")
586590
browserPoolsUpdateCmd.Flags().String("start-url", "", "Initial page to open for new browsers")
587591
browserPoolsUpdateCmd.Flags().Bool("clear-start-url", false, "Clear the pool start URL")
@@ -641,7 +645,6 @@ func runBrowserPoolsCreate(cmd *cobra.Command, args []string) error {
641645
kiosk, _ := cmd.Flags().GetBool("kiosk")
642646
profileID, _ := cmd.Flags().GetString("profile-id")
643647
profileName, _ := cmd.Flags().GetString("profile-name")
644-
saveChanges, _ := cmd.Flags().GetBool("save-changes")
645648
proxyID, _ := cmd.Flags().GetString("proxy-id")
646649
startURL, _ := cmd.Flags().GetString("start-url")
647650
extensions, _ := cmd.Flags().GetStringSlice("extension")
@@ -651,23 +654,22 @@ func runBrowserPoolsCreate(cmd *cobra.Command, args []string) error {
651654
output, _ := cmd.Flags().GetString("output")
652655

653656
in := BrowserPoolsCreateInput{
654-
Name: name,
655-
Size: size,
656-
FillRate: fillRate,
657-
TimeoutSeconds: timeout,
658-
Stealth: BoolFlag{Set: cmd.Flags().Changed("stealth"), Value: stealth},
659-
Headless: BoolFlag{Set: cmd.Flags().Changed("headless"), Value: headless},
660-
Kiosk: BoolFlag{Set: cmd.Flags().Changed("kiosk"), Value: kiosk},
661-
ProfileID: profileID,
662-
ProfileName: profileName,
663-
ProfileSaveChanges: BoolFlag{Set: cmd.Flags().Changed("save-changes"), Value: saveChanges},
664-
ProxyID: proxyID,
665-
StartURL: startURL,
666-
Extensions: extensions,
667-
Viewport: viewport,
668-
ChromePolicy: chromePolicy,
669-
ChromePolicyFile: chromePolicyFile,
670-
Output: output,
657+
Name: name,
658+
Size: size,
659+
FillRate: fillRate,
660+
TimeoutSeconds: timeout,
661+
Stealth: BoolFlag{Set: cmd.Flags().Changed("stealth"), Value: stealth},
662+
Headless: BoolFlag{Set: cmd.Flags().Changed("headless"), Value: headless},
663+
Kiosk: BoolFlag{Set: cmd.Flags().Changed("kiosk"), Value: kiosk},
664+
ProfileID: profileID,
665+
ProfileName: profileName,
666+
ProxyID: proxyID,
667+
StartURL: startURL,
668+
Extensions: extensions,
669+
Viewport: viewport,
670+
ChromePolicy: chromePolicy,
671+
ChromePolicyFile: chromePolicyFile,
672+
Output: output,
671673
}
672674

673675
c := BrowserPoolsCmd{client: &client.BrowserPools}
@@ -693,7 +695,6 @@ func runBrowserPoolsUpdate(cmd *cobra.Command, args []string) error {
693695
kiosk, _ := cmd.Flags().GetBool("kiosk")
694696
profileID, _ := cmd.Flags().GetString("profile-id")
695697
profileName, _ := cmd.Flags().GetString("profile-name")
696-
saveChanges, _ := cmd.Flags().GetBool("save-changes")
697698
proxyID, _ := cmd.Flags().GetString("proxy-id")
698699
startURL, _ := cmd.Flags().GetString("start-url")
699700
clearStartURL, _ := cmd.Flags().GetBool("clear-start-url")
@@ -705,26 +706,25 @@ func runBrowserPoolsUpdate(cmd *cobra.Command, args []string) error {
705706
output, _ := cmd.Flags().GetString("output")
706707

707708
in := BrowserPoolsUpdateInput{
708-
IDOrName: args[0],
709-
Name: name,
710-
Size: size,
711-
FillRate: fillRate,
712-
TimeoutSeconds: timeout,
713-
Stealth: BoolFlag{Set: cmd.Flags().Changed("stealth"), Value: stealth},
714-
Headless: BoolFlag{Set: cmd.Flags().Changed("headless"), Value: headless},
715-
Kiosk: BoolFlag{Set: cmd.Flags().Changed("kiosk"), Value: kiosk},
716-
ProfileID: profileID,
717-
ProfileName: profileName,
718-
ProfileSaveChanges: BoolFlag{Set: cmd.Flags().Changed("save-changes"), Value: saveChanges},
719-
ProxyID: proxyID,
720-
StartURL: startURL,
721-
ClearStartURL: clearStartURL,
722-
Extensions: extensions,
723-
Viewport: viewport,
724-
ChromePolicy: chromePolicy,
725-
ChromePolicyFile: chromePolicyFile,
726-
DiscardAllIdle: BoolFlag{Set: cmd.Flags().Changed("discard-all-idle"), Value: discardIdle},
727-
Output: output,
709+
IDOrName: args[0],
710+
Name: name,
711+
Size: size,
712+
FillRate: fillRate,
713+
TimeoutSeconds: timeout,
714+
Stealth: BoolFlag{Set: cmd.Flags().Changed("stealth"), Value: stealth},
715+
Headless: BoolFlag{Set: cmd.Flags().Changed("headless"), Value: headless},
716+
Kiosk: BoolFlag{Set: cmd.Flags().Changed("kiosk"), Value: kiosk},
717+
ProfileID: profileID,
718+
ProfileName: profileName,
719+
ProxyID: proxyID,
720+
StartURL: startURL,
721+
ClearStartURL: clearStartURL,
722+
Extensions: extensions,
723+
Viewport: viewport,
724+
ChromePolicy: chromePolicy,
725+
ChromePolicyFile: chromePolicyFile,
726+
DiscardAllIdle: BoolFlag{Set: cmd.Flags().Changed("discard-all-idle"), Value: discardIdle},
727+
Output: output,
728728
}
729729

730730
c := BrowserPoolsCmd{client: &client.BrowserPools}
@@ -772,23 +772,18 @@ func runBrowserPoolsFlush(cmd *cobra.Command, args []string) error {
772772
return c.Flush(cmd.Context(), BrowserPoolsFlushInput{IDOrName: args[0]})
773773
}
774774

775-
func buildProfileParam(profileID, profileName string, saveChanges BoolFlag) (*kernel.BrowserProfileParam, error) {
775+
// resolvePoolProfile validates and resolves a pool profile selection. Browser
776+
// pools have their own profile type with no save_changes; this helper works for
777+
// both create and update param types by returning the resolved id/name plus
778+
// whether a profile was selected at all.
779+
func resolvePoolProfile(profileID, profileName string) (id, name string, set bool, err error) {
776780
if profileID != "" && profileName != "" {
777-
return nil, fmt.Errorf("must specify at most one of --profile-id or --profile-name")
781+
return "", "", false, fmt.Errorf("must specify at most one of --profile-id or --profile-name")
778782
}
779783
if profileID == "" && profileName == "" {
780-
return nil, nil
784+
return "", "", false, nil
781785
}
782-
783-
profile := kernel.BrowserProfileParam{
784-
SaveChanges: kernel.Bool(saveChanges.Value),
785-
}
786-
if profileID != "" {
787-
profile.ID = kernel.String(profileID)
788-
} else if profileName != "" {
789-
profile.Name = kernel.String(profileName)
790-
}
791-
return &profile, nil
786+
return profileID, profileName, true, nil
792787
}
793788

794789
func validateStartURLFlag(startURL string) error {
@@ -847,15 +842,8 @@ func formatFillRate(rate int64) string {
847842
return "-"
848843
}
849844

850-
func formatProfile(profile kernel.BrowserProfile) string {
851-
name := util.FirstOrDash(profile.Name, profile.ID)
852-
if name == "-" {
853-
return "-"
854-
}
855-
if profile.SaveChanges {
856-
return fmt.Sprintf("%s (save changes: true)", name)
857-
}
858-
return fmt.Sprintf("%s (save changes: false)", name)
845+
func formatProfile(profile kernel.BrowserPoolBrowserPoolConfigProfile) string {
846+
return util.FirstOrDash(profile.Name, profile.ID)
859847
}
860848

861849
func formatExtensions(extensions []kernel.BrowserExtension) string {

cmd/browsers.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2748,7 +2748,17 @@ followed automatically by Chromium.`,
27482748
telemetryStream.Flags().StringSlice("types", []string{}, "Filter by event type (e.g. network_response,console_error)")
27492749
telemetryStream.Flags().Int64("seq", -1, "Resume after sequence number N (Last-Event-ID); replays events with seq > N. Default -1 streams from now")
27502750
telemetryStream.Flags().StringP("output", "o", "", "Output format: json for newline-delimited JSON envelopes")
2751+
telemetryStream.Flags().String("replay", "", "Replay buffered events on connect: --replay=all starts from the oldest retained event")
2752+
telemetryStream.MarkFlagsMutuallyExclusive("seq", "replay")
27512753
telemetryRoot.AddCommand(telemetryStream)
2754+
2755+
telemetryEvents := &cobra.Command{Use: "events <id>", Short: "Read historical telemetry events (paged)", Args: cobra.ExactArgs(1), RunE: runBrowsersTelemetryEvents}
2756+
telemetryEvents.Flags().Int64("limit", 0, "Maximum number of events per page (default 20)")
2757+
telemetryEvents.Flags().Int64("offset", 0, "Pagination cursor: pass the X-Next-Offset from a previous response")
2758+
telemetryEvents.Flags().String("since", "", "Window start: RFC-3339 timestamp or a duration like 5m (default 5m). Ignored when --offset is set")
2759+
telemetryEvents.Flags().String("until", "", "Window end (exclusive): RFC-3339 timestamp or a duration like 5m")
2760+
telemetryEvents.Flags().StringP("output", "o", "", "Output format: json")
2761+
telemetryRoot.AddCommand(telemetryEvents)
27522762
browsersCmd.AddCommand(telemetryRoot)
27532763

27542764
// no flags for view; it takes a single positional argument

0 commit comments

Comments
 (0)