Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ Commands with JSON output support:
- `-H, --headless` - Launch browser without GUI access
- `--kiosk` - Launch browser in kiosk mode
- `--start-url <url>` - Initial page to open on launch
- `--name <name>` - Optional unique name for the session (set at creation; used to find it later by name)
- `--name <name>` - Optional unique name for the session (used to find it later by name; can be changed with `browsers update --name`)
- `--tag <KEY=VALUE>` - Set a tag on the session, repeatable; up to 50 pairs
- `--pool-id <id>` - Acquire a browser from the specified pool (mutually exclusive with --pool-name; ignores other session flags). `--name`/`--tag` still apply to the acquired session.
- `--pool-name <name>` - Acquire a browser from the pool name (mutually exclusive with --pool-id; ignores other session flags)
Expand All @@ -228,6 +228,10 @@ Commands with JSON output support:
- `kernel browsers get <id-or-name>` - Get detailed browser session info by ID or name
- `--output json`, `-o json` - Output raw JSON object
- `kernel browsers update <id-or-name>` - Update a running browser session by ID or name
- `--name <name>` - Set a new unique name for the session (mutually exclusive with `--clear-name`)
- `--clear-name` - Clear the session name
- `--tag <KEY=VALUE>` - Set a tag, repeatable; up to 50 pairs. Replaces the entire tag set (not merged); mutually exclusive with `--clear-tags`
- `--clear-tags` - Remove all tags from the session
- `--telemetry=all` - Enable telemetry for all categories
- `--telemetry=off` - Disable telemetry
- `--telemetry=<list>` - Per-category config, e.g. `--telemetry=network=on,page=off`
Expand Down
81 changes: 77 additions & 4 deletions cmd/browsers.go
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,12 @@ type BrowsersUpdateInput struct {
Viewport string
Force bool
Telemetry string
Name string
SetName bool
ClearName bool
Tags map[string]string
SetTags bool
ClearTags bool
Output string
}

Expand Down Expand Up @@ -650,9 +656,37 @@ func (b BrowsersCmd) Update(ctx context.Context, in BrowsersUpdateInput) error {
return fmt.Errorf("cannot specify both --proxy-id and --clear-proxy")
}

// Cannot specify both --name and --clear-name
if in.SetName && in.ClearName {
return fmt.Errorf("cannot specify both --name and --clear-name")
}

// Cannot specify both --tag and --clear-tags. Use SetTags (the raw flag
// signal) as well as the parsed map so the check still fires when every
// --tag value was malformed and dropped to an empty map.
if (in.SetTags || len(in.Tags) > 0) && in.ClearTags {
return fmt.Errorf("cannot specify both --tag and --clear-tags")
}

// --tag was provided but parsed to zero valid pairs (every value malformed).
// Treat as a user error rather than silently leaving tags unchanged.
if in.SetTags && len(in.Tags) == 0 {
return fmt.Errorf("no valid --tag KEY=VALUE pairs provided")
}

// --name must carry a value; clearing is done explicitly via --clear-name.
// (A set name combined with --clear-name is already rejected above, so the
// ClearName case cannot reach here.)
if in.SetName && in.Name == "" {
return fmt.Errorf("--name requires a non-empty value; use --clear-name to clear the name")
}

hasProxyChange := in.ProxyID != "" || in.ClearProxy
hasProfileChange := in.ProfileID != "" || in.ProfileName != ""
hasViewportChange := in.Viewport != ""
// By this point a set name is guaranteed non-empty (the guard above rejects --name "").
hasNameChange := in.SetName || in.ClearName
hasTagsChange := len(in.Tags) > 0 || in.ClearTags

// Validate --save-changes is only used with a profile
if in.ProfileSaveChanges.Set && !hasProfileChange {
Expand All @@ -665,12 +699,27 @@ func (b BrowsersCmd) Update(ctx context.Context, in BrowsersUpdateInput) error {
}

// Validate that at least one update option is provided
if !hasProxyChange && !hasProfileChange && !hasViewportChange && in.Telemetry == "" {
return fmt.Errorf("must specify at least one of: --proxy-id, --clear-proxy, --profile-id, --profile-name, --viewport, or --telemetry")
if !hasProxyChange && !hasProfileChange && !hasViewportChange && in.Telemetry == "" && !hasNameChange && !hasTagsChange {
return fmt.Errorf("must specify at least one of: --proxy-id, --clear-proxy, --profile-id, --profile-name, --viewport, --telemetry, --name, --clear-name, --tag, or --clear-tags")
}

params := kernel.BrowserUpdateParams{}

// Handle name changes
if in.ClearName {
params.Name = kernel.Opt("")
} else if in.SetName {
params.Name = kernel.Opt(in.Name)
}

// Handle tag changes. Tags are a full replace, not a merge: providing --tag
// replaces the entire set, and --clear-tags removes all tags.
if in.ClearTags {
params.Tags = kernel.Tags{}
} else if len(in.Tags) > 0 {
params.Tags = kernel.Tags(in.Tags)
}

// Handle proxy changes
if in.ClearProxy {
params.ProxyID = kernel.Opt("")
Expand Down Expand Up @@ -734,6 +783,12 @@ func (b BrowsersCmd) Update(ctx context.Context, in BrowsersUpdateInput) error {
}

pterm.Success.Printf("Updated browser %s\n", browser.SessionID)
if hasNameChange {
pterm.Info.Printf("Name: %s\n", util.OrDash(browser.Name))
}
if hasTagsChange {
pterm.Info.Printf("Tags: %s\n", util.OrDash(formatTags(browser.Tags)))
}
if in.Telemetry != "" {
printTelemetrySummary(browser.Telemetry)
}
Expand Down Expand Up @@ -2291,8 +2346,12 @@ Supported operations:
- Load a profile into a session that doesn't have one (--profile-id or --profile-name)
- Change viewport dimensions (--viewport)
- Force viewport resize during active live view or recording (--force with --viewport)
- Rename or clear the session name (--name or --clear-name)
- Replace or clear the session tags (--tag or --clear-tags)

Note: Profiles can only be loaded into sessions that don't already have a profile.`,
Notes:
- Profiles can only be loaded into sessions that don't already have a profile.
- --tag replaces the entire tag set (it is not merged with existing tags).`,
Args: func(cmd *cobra.Command, args []string) error {
if len(args) == 0 {
return fmt.Errorf("missing required argument: browser ID or name\n\nUsage: kernel browsers update <id-or-name> [flags]")
Expand Down Expand Up @@ -2332,6 +2391,10 @@ func init() {
browsersUpdateCmd.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")
browsersUpdateCmd.Flags().Bool("force", false, "Force viewport resize even when a live view or recording/replay is active")
browsersUpdateCmd.Flags().String("telemetry", "", "Update telemetry: --telemetry=all (reset to default set), --telemetry=off (disable), or --telemetry=console,network (merge those categories into the current selection)")
browsersUpdateCmd.Flags().String("name", "", "Set a new unique name for the browser session (mutually exclusive with --clear-name)")
browsersUpdateCmd.Flags().Bool("clear-name", false, "Clear the browser session name")
browsersUpdateCmd.Flags().StringArray("tag", nil, "Set a tag KEY=VALUE (repeatable; up to 50 pairs). Replaces the entire tag set; mutually exclusive with --clear-tags")
browsersUpdateCmd.Flags().Bool("clear-tags", false, "Remove all tags from the browser session")

browsersCmd.AddCommand(browsersListCmd)
browsersCmd.AddCommand(browsersCreateCmd)
Expand Down Expand Up @@ -2598,7 +2661,7 @@ func init() {
browsersCreateCmd.Flags().String("pool-id", "", "Browser pool ID to acquire from (mutually exclusive with --pool-name)")
browsersCreateCmd.Flags().String("pool-name", "", "Browser pool name to acquire from (mutually exclusive with --pool-id)")
browsersCreateCmd.Flags().String("telemetry", "", "Configure telemetry (opt-in): --telemetry=all (default set), --telemetry=off (disable), or --telemetry=console,network (capture exactly those categories)")
browsersCreateCmd.Flags().String("name", "", "Optional unique name for the browser session (used to find it later; set at creation only)")
browsersCreateCmd.Flags().String("name", "", "Optional unique name for the browser session (used to find it later; can be changed with 'browsers update --name')")
browsersCreateCmd.Flags().StringArray("tag", nil, "Set a tag KEY=VALUE on the session (repeatable; up to 50 pairs)")

// curl
Expand Down Expand Up @@ -2858,6 +2921,10 @@ func runBrowsersUpdate(cmd *cobra.Command, args []string) error {
viewport, _ := cmd.Flags().GetString("viewport")
force, _ := cmd.Flags().GetBool("force")
telemetry, _ := cmd.Flags().GetString("telemetry")
name, _ := cmd.Flags().GetString("name")
clearName, _ := cmd.Flags().GetBool("clear-name")
tags := tagsFromFlag(cmd, "tag")
clearTags, _ := cmd.Flags().GetBool("clear-tags")

svc := client.Browsers
b := BrowsersCmd{browsers: &svc}
Expand All @@ -2871,6 +2938,12 @@ func runBrowsersUpdate(cmd *cobra.Command, args []string) error {
Viewport: viewport,
Force: force,
Telemetry: telemetry,
Name: name,
SetName: cmd.Flags().Changed("name"),
ClearName: clearName,
Tags: tags,
SetTags: cmd.Flags().Changed("tag"),
ClearTags: clearTags,
Output: out,
})
}
Expand Down
Loading
Loading