Skip to content

feat: custom tab group names and colors per session#64

Open
remorses wants to merge 1 commit intomainfrom
feat/custom-tab-groups
Open

feat: custom tab group names and colors per session#64
remorses wants to merge 1 commit intomainfrom
feat/custom-tab-groups

Conversation

@remorses
Copy link
Owner

@remorses remorses commented Mar 7, 2026

Sessions can now specify a custom Chrome tab group name and color via playwriter session new --name myproject --color red. Different sessions with different names get separate Chrome tab groups.

Extension (0.0.74 → 0.0.77)

  • Custom groupName/groupColor on TabInfo, multi-group syncTabGroup, retry logic for tabGroups.update() race condition
  • Fix tab group flapping: only apply group metadata on Target.createTarget, not every CDP command
  • tabsBeingMoved guard prevents programmatic ungroup from triggering disconnects

Playwriter MCP/CLI (0.0.85 → 0.0.87)

  • --name and --color options on session new
  • Group metadata flows: CLI → relay HTTP → CDP URL params → relay state → extension
  • Only inject group fields on Target.createTarget to prevent flapping

Website

  • New markdown.tsx route with safe-mdx

Backward compatible — older extensions ignore new fields, omitting options keeps default "playwriter" green group.

Sessions can now specify a custom Chrome tab group name and color via
`playwriter session new --name myproject --color red`. Different sessions
with different names get separate Chrome tab groups.

The metadata flows through: CLI options → relay HTTP → CDP URL query params →
relay state (PlaywrightClient) → forwardCDPCommand params → extension TabInfo →
chrome.tabGroups API.

Key changes:

**Extension (0.0.74 → 0.0.77)**
- Add groupName/groupColor fields to TabInfo
- Rewrite syncTabGroup to manage multiple named groups independently
- Add updateTabGroupWithRetry to handle Chrome's race condition where
  tabGroups.update() silently fails right after tabs.group()
- Fix tab group flapping bug: only apply group metadata on
  Target.createTarget, not on every CDP command. Broadcast commands like
  Target.setAutoAttach were overwriting unrelated tabs' group metadata
- Add tabsBeingMoved guard set so programmatic ungroup/regroup during
  syncTabGroup doesn't trigger disconnect via onUpdated handler
- Narrow store subscriber to only trigger syncTabGroup on group-relevant
  field changes (state, groupName, groupColor)

**Playwriter MCP/CLI (0.0.85 → 0.0.87)**
- Add --name and --color options to `session new` CLI command
- Forward groupName/groupColor through getCdpUrl query params
- Store group metadata on PlaywrightClient in relay state
- Only inject group fields into forwardCDPCommand on Target.createTarget
  to prevent the flapping bug
- Pass clientId through handleCDPCommand so relay can look up group metadata

**Website**
- Add markdown.tsx route using safe-mdx for markdown-driven editorial pages

Backward compatible: older extensions ignore the new fields, omitting
options preserves the default 'playwriter' green group.
Copilot AI review requested due to automatic review settings March 7, 2026 21:35
@vercel
Copy link

vercel bot commented Mar 7, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
playwriter-website Ready Ready Preview, Comment Mar 7, 2026 9:35pm

Request Review

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds per-session Chrome tab group naming/color support end-to-end (CLI → relay → extension) and introduces a new website route that renders the editorial page from markdown via safe-mdx.

Changes:

  • Propagate groupName / groupColor from playwriter session new --name/--color through relay state and CDP URL params to the extension.
  • Update extension tab-group synchronization to support multiple managed groups, reduce “group flapping”, and add retry logic for chrome.tabGroups.update() race conditions.
  • Add website/src/routes/markdown.tsx rendered via safe-mdx and include the new dependency.

Reviewed changes

Copilot reviewed 17 out of 18 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
website/src/routes/markdown.tsx New markdown-driven editorial page rendered via safe-mdx with component overrides.
website/package.json Adds safe-mdx dependency for the new markdown route.
pnpm-lock.yaml Lockfile updates for safe-mdx and related dependency graph changes.
playwriter/src/utils.ts Adds groupName/groupColor query params to generated CDP URLs.
playwriter/src/skill.md Documents new --name/--color options for sessions.
playwriter/src/relay-state.ts Stores groupName/groupColor on PlaywrightClient in relay state.
playwriter/src/protocol.ts Extends forwardCDPCommand params to optionally include tab group metadata.
playwriter/src/executor.ts Threads session group metadata into cdpConfig for CDP URL generation.
playwriter/src/cli.ts Adds session new --name/--color options with color validation and forwards to relay.
playwriter/src/cdp-relay.ts Reads group metadata from CDP URL params, stores per-client metadata, and injects it only on Target.createTarget.
playwriter/package.json Bumps Playwriter version to 0.0.87.
playwriter/CHANGELOG.md Documents new session grouping feature and flapping bug fix behavior.
extension/src/types.ts Extends TabInfo with optional groupName/groupColor.
extension/src/background.ts Implements multi-group syncTabGroup, retry logic for group updates, and guards against programmatic ungroup triggering disconnects.
extension/package.json Bumps extension package version to 0.0.76.
extension/manifest.json Bumps extension manifest version to 0.0.77.
extension/CHANGELOG.md Documents the session grouping feature, race retry, and flapping/disconnect fixes.
AGENTS.md Adds guidance about opensrc/ dependency source reference workflow.
Files not reviewed (1)
  • pnpm-lock.yaml: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

const tabsInDupe = await chrome.tabs.query({ groupId: dupe.id })
const idsToUngroup = tabsInDupe.map((t) => t.id).filter((id): id is number => id !== undefined)
if (idsToUngroup.length > 0) {
await chrome.tabs.ungroup(idsToUngroup)
Copy link

Copilot AI Mar 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When consolidating duplicate Chrome tab groups, tabs are ungrouped without marking them in tabsBeingMoved. This can trigger chrome.tabs.onUpdated with groupId=-1 and be misinterpreted as a manual removal, causing disconnectTab() to run (the exact flapping/disconnect loop this PR is trying to prevent). Wrap this chrome.tabs.ungroup(idsToUngroup) call with the same tabsBeingMoved add/remove guard used elsewhere in syncTabGroup (and ideally a try/finally).

Suggested change
await chrome.tabs.ungroup(idsToUngroup)
try {
// Mark tabs as being moved so onUpdated doesn't disconnect them when
// chrome.tabs.ungroup fires groupId=-1
for (const id of idsToUngroup) {
tabsBeingMoved.add(id)
}
await chrome.tabs.ungroup(idsToUngroup)
} catch (e: any) {
logger.debug('Failed to ungroup tabs while removing duplicate group:', idsToUngroup, e.message)
} finally {
for (const id of idsToUngroup) {
tabsBeingMoved.delete(id)
}
}

Copilot uses AI. Check for mistakes.
Comment on lines 175 to 181
export function addPlaywrightClient(
state: RelayState,
{ id, extensionId, ws }: { id: string; extensionId: string | null; ws: WSContext },
{ id, extensionId, ws, groupName, groupColor }: { id: string; extensionId: string | null; ws: WSContext; groupName?: string; groupColor?: string },
): RelayState {
const newClients = new Map(state.playwrightClients)
newClients.set(id, { id, extensionId, ws })
newClients.set(id, { id, extensionId, ws, groupName, groupColor })
return { ...state, playwrightClients: newClients }
Copy link

Copilot AI Mar 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

addPlaywrightClient now stores groupName/groupColor, but existing unit tests only assert extensionId/ws. Since these fields are part of the new session grouping feature, please extend the existing addPlaywrightClient test coverage to assert that provided groupName/groupColor are persisted in state (and remain optional when omitted).

Copilot uses AI. Check for mistakes.
Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 96575c1b69

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +585 to +587
const groupFields = method === 'Target.createTarget' && (client?.groupName || client?.groupColor)
? { groupName: client.groupName, groupColor: client.groupColor }
: {}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Forward group metadata for auto-created initial tabs

When PLAYWRITER_AUTO_ENABLE is enabled and no targets exist, the first page is created via the Target.setAutoAttach path (maybeAutoCreateInitialTab) rather than a Target.createTarget command. Because groupFields are currently gated to method === 'Target.createTarget', that initial tab never receives groupName/groupColor and is grouped under the default "playwriter" group, so sessions started with different --name/--color can still collide until they open another page.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants