[STG-2422] feat(cli): named contexts (local name→ID map)#2284
Conversation
🦋 Changeset detectedLatest commit: 00fdd03 The changes in this PR will be included in the next version bump. This PR includes changesets to release 0 packagesWhen changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
There was a problem hiding this comment.
6 issues found and verified against the latest diff
Confidence score: 3/5
- In
packages/cli/src/commands/cloud/contexts/delete.ts, remote deletion can succeed but local alias cleanup can still throw, so users may see a failure after the context is already gone and retry into confusing states — make local cleanup non-blocking (or clearly report partial success) before merging. - In
packages/cli/src/lib/cloud/contexts-store.ts, alias data fromcontexts.jsonis trusted without shape validation, so malformed entries can break name resolution/cleanup instead of degrading gracefully — validate and discard invalid alias entries as "no saved contexts." - In
packages/cli/src/commands/cloud/contexts/create.ts, allowing ID-shaped alias names can shadow real context IDs and break raw-ID workflows — block ID-like names (or add explicit disambiguation) before merge. - In
packages/cli/src/lib/cloud/contexts-store.ts, store writes are last-writer-wins and existingcontexts.jsonfiles may retain permissive permissions, which can cause lost updates and leave alias data more exposed than intended — add concurrency-safe write/merge handling and enforcechmod 0o600on existing files, then tightenpackages/cli/tests/contexts-store.test.tsto assert mode bits.
Tip: instead of fixing issues one by one fix them all with cubic
Re-trigger cubic
There was a problem hiding this comment.
1 issue found across 3 files (changes from recent commits).
Tip: Review your code locally with the cubic CLI to iterate faster.
Fix all with cubic | Re-trigger cubic
Tested this end-to-end — ✅ good to approveBuilt the cloud command subtree from this branch and ran the full lifecycle against live Browserbase (throwaway Verified hands-on (live API)
Name validation, the Non-blocking CLI-design suggestions (for a follow-up, not merge blockers)
Recommend merging; items 1 & 2 are worth a follow-up. — tested with Claude Code |
|
Thanks for the thorough end-to-end pass @shubh24 🙏 Folded in two of your four right away (
The other two I'd like to take as fast-follows rather than grow this PR:
Also added tests for the new resolver (unit: detailed resolution + did-you-mean ranking; CLI e2e: typo'd-name failure makes no API call) and switched the contract-test fixtures from |
There was a problem hiding this comment.
2 issues found across 10 files (changes from recent commits).
Tip: Review your code locally with the cubic CLI to iterate faster.
Re-trigger cubic
|
Update on suggestion #1 @shubh24 — decided to fold it in rather than defer. Added Verified live: That leaves only #3 (drift/ |
There was a problem hiding this comment.
1 issue found across 5 files (changes from recent commits).
Tip: Review your code locally with the cubic CLI to iterate faster.
Re-trigger cubic
Reuse a Browserbase context by a memorable name instead of its opaque ID. Browserbase contexts are ID-only with no server-side list, so a small local map at (XDG_CONFIG_HOME||~/.config)/browserbase/contexts.json gives them names. - `contexts create --name <name>` saves a name→ID alias - `contexts list` shows saved names (new command) - `contexts get|update|delete` and `sessions create --context-id` accept a saved name or a raw ID (resolver passes unknown refs through unchanged) - `contexts delete` prunes the local alias - store degrades to empty on a missing/corrupt file; alias file is 0600 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Drop the parenthetical from the `contexts list` description.
- Wrap list JSON in `{ contexts }` to match `templates list` / `skills list`
machine-readable shape (was a bare array); update e2e assertion.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- delete: prune local alias best-effort so a local cleanup failure can't turn a successful remote delete into a false-negative (P2) - store: atomic temp-file + rename write — readers never see a half-written file, and the final file is always 0600 even over a pre-existing permissive contexts.json (P2 x2) - store: sanitize entries on read; drop malformed ones instead of trusting them as ContextAlias (P2) - create/store: reject UUID-shaped names so an alias can't shadow a raw context id (real ids are UUIDs, not ctx_-prefixed) (P2) - tests: assert 0600 perm bits + pre-existing-file hardening + malformed-entry drop + UUID-name rejection Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
sanitizeContexts now also runs the name through isValidContextName, so a hand-edited contexts.json can't smuggle in an id-shaped or otherwise invalid name that would shadow a raw context id. Same rule as `create --name`. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Addresses review suggestions from @shubh24: - Typo'd/unknown context name now fails with an actionable "No saved context named X. Did you mean: <closest>?" message (levenshtein) instead of letting it hit the API as a bogus id and returning a cryptic "Invalid Context ID". Applies to contexts get/update/delete and sessions create --context-id. A context id (UUID) or known name still resolves; only unknown names fail. - Drop the unused `ContextAlias.projectId` field (was defined, never populated). - Contract-test context fixtures use a UUID instead of `ctx_123` so resolution hits the id-passthrough path and stays hermetic vs the local store. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Addresses cubic re-review: - P1: resolution no longer rejects non-UUID raw ids. A ref that's neither a known name nor a UUID now only fails when it's *close* to a saved name (typo -> "did you mean?"); otherwise it passes through to the API, preserving raw-id compatibility for any id shape. - P2: the in-memory contexts map is now a null-prototype object, so a ref like "toString"/"constructor"/"__proto__" can't read an inherited member as if it were a saved alias. Tests: prototype-key resolution returns null; unknown non-UUID ref with no close match passes through (unit + CLI e2e). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Closes the gap from @shubh24's review #1: you can now name a context you already have (an id a teammate shared, or one created on another device / outside the CLI) instead of only at create time. Local-only, mirrors the alias-save path; --force repoints an existing name. Validates the name (same rule as create --name) and rejects an empty id. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
cubic: the empty-check trimmed the id but the raw value was saved, so a whitespace-padded id would be stored and later resolved as a bogus context id. Persist the normalized (trimmed) id and echo it back. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
ed83759 to
00fdd03
Compare
What & why
Browserbase contexts are identified only by an opaque ID and the platform has no server-side list endpoint, so reusing a context today means remembering (or copy-pasting) a UUID. This is also the single most-used feature of the popular community Browserbase skill on ClawHub (jamesfincher/browserbase), which keeps a local map of named contexts.
This PR ports that ergonomic into the CLI as a thin, client-side name→ID map — no API change.
browse cloud contexts create --name github→ creates the context and saves a local aliasbrowse cloud contexts list→ shows your saved names (new command; the API has no list, so this reflects names saved on this device)contexts get|update|deleteandsessions create --context-idnow accept a saved name or a raw ID (a resolver passes unknown refs through unchanged, so raw IDs still work everywhere)contexts deleteprunes the local alias for the deleted contextThe map lives at
(XDG_CONFIG_HOME||~/.config)/browserbase/contexts.json(honoringBROWSERBASE_CONFIG_DIR), next to the CLI's existing state via the sharedresolveConfigDir()helper. The file is written0600. It stores only the same IDs the API already returns, and a missing or corrupt file degrades to "no saved contexts" rather than erroring.Linear: STG-2422
E2E Test Matrix
Run against live Browserbase with the local build (
node bin/run.js),BROWSERBASE_CONFIG_DIRpointed at a throwaway dir. Signed URLs redacted.contexts create --name e2e-smoke{"id":"45ed525f-…","uploadUrl":"<redacted>",…,"name":"e2e-smoke"}cat contexts.json{"version":1,"contexts":{"e2e-smoke":{"id":"45ed525f-…","createdAt":"2026-06-27T00:40:51Z"}}}contexts get e2e-smoke(by name){"id":"45ed525f-…","projectId":"2d228d57-…",…}gethits the real/v1/contexts/<id>.contexts list --format tableName ID Createdprod-login d98a30da 2026-06-27 00:41Zsessions create --context-id prod-login --persist(by name)27f9087a-…returned withcontextId == d98a30da-…→MATCHES name→id: Truecontexts delete prod-login(by name){"ok":true,"id":"d98a30da-…","removedAliases":["prod-login"]}thencontexts list→No saved contexts.contexts delete <raw-uuid>{"ok":true,"id":"45ed525f-…"}(noremovedAliases)pnpm test:cliTest Files 21 passed (21) · Tests 310 passed (310)contexts-storeunit tests +contexts-namedCLI-level e2e (fake server) + updated surface test.pnpm linttsc --noEmitall cleanNotes
browse: patch(matches how the CLI bumps;browseis in the changesetignorelist but still gets release-impacting patches by convention).🤖 Generated with Claude Code
Summary by cubic
Add named contexts to the CLI so you can reuse a Browserbase context by name instead of copying IDs. Implements Linear STG-2422 with a local name→ID map, typo hints, raw‑ID compatibility, and a new
contexts addcommand; no API changes.New Features
browse cloud contexts create --name <name>saves a local alias and returns the name;browse cloud contexts add <name> <id>names an existing context (trims the ID, rejects empty; use--forceto overwrite).browse cloud contexts listshows saved names on this device (--jsonreturns{ "contexts": [...] }).browse cloud contexts get|update|deleteandbrowse cloud sessions create --context-idaccept a saved name or a raw ID. Unknown names close to a saved one fail early with a “did you mean?” hint; unknown refs otherwise pass through so non-UUID IDs still work.contexts deleteprunes aliases for the deleted ID and includesremovedAliases(best effort).Notes
(XDG_CONFIG_HOME||~/.config)/browserbase/contexts.json(honorsBROWSERBASE_CONFIG_DIR), written 0600 via atomic write; missing/corrupt files behave as empty. The map is prototype-safe, rejects UUID-shaped names, and sanitizes malformed entries on read; names must start alphanumeric, allow letters/digits/._-, max 64, and duplicates are blocked unless--force.Written for commit 00fdd03. Summary will update on new commits.