Add session name & tags to browsers update (kernel-go-sdk v0.66.0)#184
Conversation
Bumps kernel-go-sdk v0.65.0 -> v0.66.0, which adds Name and Tags to BrowserUpdateParams (PATCH /browser). The `browsers update <id-or-name>` command, which #177 left creation-only, can now patch them: --name <str> set/rename the session --clear-name clear the name (sends "name":"") --tag KEY=VALUE replace the entire tag set (repeatable, full replace) --clear-tags clear all tags (sends "tags":{}) Mirrors the existing --clear-proxy convention and honors the SDK semantics exactly: omit = unchanged, empty = clear, tags = full replace. Validation rejects --name/--clear-name and --tag/--clear-tags conflicts, guards against an accidental --name "", and a SetName/SetTags flag signal keeps the conflict and "at least one option" checks correct even when a malformed --tag is dropped to an empty map. Updates the create --name and update --tag help/README for accuracy, and adds unit tests across the new flags, clear/omit marshaling, and the malformed-tag edge cases. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
|
Created a monitoring plan for this PR. What this PR does: Lets users rename and retag running browser sessions from the CLI — Intended effect:
Risks:
Status updates will be posted automatically on this PR as monitoring progresses. |
Sayan-
left a comment
There was a problem hiding this comment.
Approving. This is correct and matches the API contract (checked the v0.66 SDK: omit = unchanged, "" clears name, {} clears tags, tags are a full replace). Tests cover the tricky cases well. Two non-blocking notes for later, no need to hold the merge:
-
The Set/Clear/value flags do the same job twice. Each field carries a value, a Clear bool, and a Set bool, and the validation reads different combos of them (name keys off SetName, tags off len(Tags)). It works, but the "did the user pass this flag?" signal gets dropped in tagsFromFlag (malformed tags become nil, same as "not passed") and then rebuilt via cmd.Flags().Changed(...). The cleaner version is one signal per field, with tagsFromFlag reporting whether anything was provided. That also tidies up the same edge in create. Behavior stays identical, so it's fine as a follow-up.
-
--name "" is rejected by us, not the API. The spec treats an empty name as a valid clear, same as proxy_id. We reject it and point people at --clear-name, which is the only reason the extra name signal exists. Reasonable guardrail, just noting it's a CLI choice rather than a requirement. Fine either way.
Neither blocks. Ship it.
Thanks Sayan! Will merge this in as-is and followup with a new PR to address your first point (1). |
#186) ## Summary `tagsFromFlag` now reports whether the `--tag` flag was *provided* (independent of whether its values parsed), so `runBrowsersUpdate` no longer rebuilds that signal via `cmd.Flags().Changed("tag")` — `BrowsersUpdateInput.SetTags` is renamed to `TagsProvided` and sourced from the helper, with the three other call sites discarding the new bool. This is a behavior-preserving structural cleanup (non-blocking follow-up to #184) that leaves the `--name`/`--clear-name` side untouched, since it has no equivalent redundancy. Two helper tests were added to pin the newly-distinguished "absent" vs. "provided-but-all-malformed" states. ## Test plan - [x] `go build ./...`, `go vet ./cmd/`, `gofmt -l` clean - [x] `go test ./...` green (incl. `TestBrowsersUpdate_*`, `TestTagsFromFlag_*`, `TestParseKeyValueSpecs`) - [x] CLI smoke: `--tag foo` → "No valid --tag KEY=VALUE pairs provided"; `--tag foo --clear-tags` → "Cannot specify both --tag and --clear-tags" 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > CLI-only flag parsing refactor with regression tests; intended to preserve browsers update validation behavior. > > **Overview** > **`tagsFromFlag`** now returns parsed tags plus a **`provided`** bool from `pflag`’s `Changed`, so an empty `--tag=` still counts as the user passing `--tag` (not a silent no-op). > > **`browsers update`** wires that bool into **`BrowsersUpdateInput.TagsProvided`** (replacing **`SetTags`** and duplicate `Changed("tag")` in the runner). Validation for conflicting **`--clear-tags`**, all-malformed tags, and lone empty **`--tag`** still keys off “flag was provided,” not only a non-empty map. > > List/create/acquire call sites adopt the new two-value return and ignore **`provided`**. Tests add **`tagsCmdWithArgs`** and cases for absent flag, all-malformed, and empty **`--tag=`**. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 282203a. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY --> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Summary
Bumps
kernel-go-sdkv0.65.0 → v0.66.0, which addsName/TagstoBrowserUpdateParams(PATCH /browser), and uses it to givebrowsers update <id-or-name>the--name/--clear-name/--tag KEY=VALUE/--clear-tagsflags that #177 had left creation-only. The flags mirror the existing--clear-proxyconvention and honor the SDK semantics exactly (omit = unchanged, empty = clear, tags = full replace), with validation that rejects--name/--clear-nameand--tag/--clear-tagsconflicts, guards against an accidental--name "", and stays correct via aSetName/SetTagsflag signal even when a malformed--tagis dropped to an empty map. Also refreshes the now-stalecreate --namehelp and theupdate --tagcap in help/README, and adds unit tests across the new flags, clear/omit marshaling, and the malformed-tag edge cases.Test Plan
go build ./...,go vet ./cmd/,gofmt— cleango test ./...— passing (16 newTestBrowsersUpdate_*cases)--helpshows flags; every validation path errors before any API calllocalhost:3001): 18/19 🌐 rows pass, 0 product defects — full-replace tags,--name-only does not clobber tags (omit = unchanged), clear name/tags, by-id/by-name resolution, not-found, JSON echo, name+telemetry, and the 50-tag cap (Invalid_tags: too many tags: 51 (maximum 50)). Sessions were cleaned up. The one unrun row, B3 (rename-collision between two concurrent active sessions), isn't exercisable on the local stack (it returnsCapacity_exhaustedfor a second simultaneous browser); name uniqueness is server-enforced and the CLI only relays the error.Manual test matrix
Status: ✅ = verified locally (path returns before any API call, or pinned by a named unit test asserting the exact forwarded params / JSON) · 🌐 = needs a live Kernel API round-trip (not yet run here).
Notes
ptermcapitalizes the first letter (Cannot specify…,--Name requires…); the rawfmt.Errorfstrings are lowercase — same error.Name:/Tags:lines echo the server's returned values, not the request. Unit tests pin the request body (✅); the displayed value is a 🌐 observation — except after a clear, whereName: -/Tags: -is correct regardless.disable_default_proxy(also new in v0.66) is intentionally not exposed by this PR.Preconditions for 🌐 rows: one session with a known starting name + tags (
browsers create --name mtx-base --tag a=1 --tag team=qa); D2 needs the session to start with{a=1}then run--tag b=2; B2/B3 need a second session (--name mtx-taken) so a colliding active name exists.A. Build / help
go build ./cmd/kernelbrowsers update --help--name,--clear-name,--tag,--clear-tags; the--tagline carries the full-replace + "up to 50 pairs" notesLonghelp documents opsbrowsers update --helpB. Set name
browsers update <id> --name new-name{"name":"new-name"}✅; outputUpdated browser <id>thenName: new-name(value echoed from server response) 🌐browsers update old-name --name newerbrowsers update <id> --name takenConflict: browser session name already existsC. Clear name
browsers update <id> --clear-name{"name":""}; outputName: ---name ""rejected (use --clear-name)browsers update <id> --name ""--name requires a non-empty value; use --clear-name to clear the name--name=(explicit empty) rejectedbrowsers update <id> --name=D. Set tags (full replace)
browsers update <id> --tag team=backend --tag env=prod{"tags":{"team":"backend","env":"prod"}}✅; outputTags: env=prod, team=backend(sorted; echoed from server response) 🌐{a=1}, run--tag b=2{b=2}only —ais gonebrowsers update <id> --tag region.us=1"region.us":"1"--tag×51=browsers update <id> --tag url=a=b=only → body{"tags":{"url":"a=b"}}(not dropped as malformed)k=v=w→k:"v=w"); 🌐 (persisted)E. Clear tags
browsers update <id> --clear-tags{"tags":{}}; outputTags: -F. Combined name + tags
browsers update <id> --name combo --tag k=v"name":"combo"and"tags":{"k":"v"}browsers update <id> --clear-name --tag env=prod{"name":"","tags":{"env":"prod"}}browsers update <id> --name renamed --clear-tags{"name":"renamed","tags":{}}G. Combine with existing update flags
browsers update <id> --proxy-id <pid> --name combo --tag k=vproxy_id,name,tagsbrowsers update <id> --name n --telemetry=all--nameonlyH. Conflict & "at least one" validation
--name+--clear-namebrowsers update <id> --name x --clear-namecannot specify both --name and --clear-name--tag+--clear-tagsbrowsers update <id> --tag a=1 --clear-tagscannot specify both --tag and --clear-tagsbrowsers update <id>must specify at least one of: …(full list of 10 flags, ending--name, --clear-name, --tag, or --clear-tags) — substring checkbrowsers update <id> --name xbrowsers update <id> --tag k=vI. Malformed-tag edge cases
--tagvalues malformed, alonebrowsers update <id> --tag fooIgnoring malformed tag: foo, then errorno valid --tag KEY=VALUE pairs provided(not the generic "at least one")--tag+--clear-tagsstill conflictsbrowsers update <id> --tag foo --clear-tagscannot specify both --tag and --clear-tags(does NOT silently clear)browsers update <id> --tag a=1 --tag badbad, replaces tag set with{a=1}onlyJ. ID-vs-name resolution & errors
browsers update <cuid> --name nbrowsers update <name> --name n2browsers update nonexistent --name nK. JSON output
browsers update <id> --name n --tag k=v -o jsonBrowserUpdateResponseJSON includingnameandtags-o yamlrejectedbrowsers update <id> --name n -o yamlunsupported --output value "yaml"; use "json"…L. Round-trip / persistence
getreflects rename--name n→browsers get <id>getreflects tag replace--tag k=v→browsers get <id>get/listreflect clears--clear-name/--clear-tags→get&list --querylist --tagno longer matcheslist --tagfilter after replacebrowsers list --tag k=vlistName column after rename--name newname→browsers listnewnamefor that session🤖 Generated with Claude Code
Note
Low Risk
CLI-only changes to browser session metadata with local validation and tests; API behavior is delegated to the bumped SDK.
Overview
Bumps kernel-go-sdk to v0.66.0 and wires
browsers updateto the new PATCH fields for session name and tags, so renaming and retagging no longer require recreating a session.kernel browsers updategains--name/--clear-nameand--tag/--clear-tags, following the same omit-vs-clear pattern as--clear-proxy: fields are omitted when unchanged, empty values clear, and--tagfully replaces the tag set (not a merge). Client-side validation rejects conflicting flag pairs, empty--name, and malformed-only--taginput (usingSetName/SetTagsso edge cases still fail before the API). Success output echoes Name / Tags when those were updated; README andcreate --namehelp note that names can be changed via update.Adds broad
TestBrowsersUpdate_*coverage for param forwarding, JSON marshaling, and validation edge cases.Reviewed by Cursor Bugbot for commit feb115c. Bugbot is set up for automated code reviews on this repo. Configure here.