From a039287b6367f5e475933268973cef5ef4124bce Mon Sep 17 00:00:00 2001
From: Dan Shapiro <3732858+danshapiro@users.noreply.github.com>
Date: Wed, 12 Aug 2026 18:43:49 -0700
Subject: [PATCH] fix(context-menu): restore pane header targeting
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Preserve the pane-header automation marker while attaching its tab and pane identity, then resolve that marker through the existing pane context-menu target. This prevents header context gestures from falling back to the global menu.
Add direct parser and rendering coverage for valid and incomplete pane identity.
🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier)
Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>
---
.../context-menu/context-menu-utils.ts | 4 +++
src/components/panes/PaneHeader.tsx | 2 ++
.../context-menu/context-menu-utils.test.ts | 29 +++++++++++++++++++
.../components/panes/PaneHeader.test.tsx | 19 ++++++++++++
4 files changed, 54 insertions(+)
diff --git a/src/components/context-menu/context-menu-utils.ts b/src/components/context-menu/context-menu-utils.ts
index 01fcacc9a..cfe093f3a 100644
--- a/src/components/context-menu/context-menu-utils.ts
+++ b/src/components/context-menu/context-menu-utils.ts
@@ -67,6 +67,10 @@ export function parseContextTarget(contextId: ContextId, data: ContextDataset):
return data.tabId && data.paneId
? { kind: 'pane', tabId: data.tabId, paneId: data.paneId }
: null
+ case ContextIds.PaneHeader:
+ return data.tabId && data.paneId
+ ? { kind: 'pane', tabId: data.tabId, paneId: data.paneId }
+ : null
case ContextIds.PaneDivider:
return data.tabId && data.splitId
? { kind: 'pane-divider', tabId: data.tabId, splitId: data.splitId }
diff --git a/src/components/panes/PaneHeader.tsx b/src/components/panes/PaneHeader.tsx
index 7e628281f..7f979e55f 100644
--- a/src/components/panes/PaneHeader.tsx
+++ b/src/components/panes/PaneHeader.tsx
@@ -126,6 +126,8 @@ export default function PaneHeader({
: isActive ? 'bg-muted' : 'bg-muted/50 text-muted-foreground'
)}
data-context={ContextIds.PaneHeader}
+ data-tab-id={tabId}
+ data-pane-id={paneId}
onDoubleClick={isRenaming ? undefined : onDoubleClick}
role="banner"
aria-label={`Pane: ${title}`}
diff --git a/test/unit/client/components/context-menu/context-menu-utils.test.ts b/test/unit/client/components/context-menu/context-menu-utils.test.ts
index 955230047..9ca5409d0 100644
--- a/test/unit/client/components/context-menu/context-menu-utils.test.ts
+++ b/test/unit/client/components/context-menu/context-menu-utils.test.ts
@@ -54,6 +54,35 @@ describe('parseContextTarget', () => {
expect(result).toEqual({ kind: 'tab', tabId: 'tab-1' })
})
+ it('parseContextTarget for PaneHeader returns the exact pane target', () => {
+ const result = parseContextTarget(ContextIds.PaneHeader, {
+ tabId: 'tab-header',
+ paneId: 'pane-header',
+ })
+
+ expect(result).toEqual({
+ kind: 'pane',
+ tabId: 'tab-header',
+ paneId: 'pane-header',
+ })
+ })
+
+ it('parseContextTarget for PaneHeader returns null when tabId is missing', () => {
+ const result = parseContextTarget(ContextIds.PaneHeader, {
+ paneId: 'pane-header',
+ })
+
+ expect(result).toBeNull()
+ })
+
+ it('parseContextTarget for PaneHeader returns null when paneId is missing', () => {
+ const result = parseContextTarget(ContextIds.PaneHeader, {
+ tabId: 'tab-header',
+ })
+
+ expect(result).toBeNull()
+ })
+
it('parseContextTarget for FreshAgent preserves pane and session flavor identity', () => {
const result = parseContextTarget(ContextIds.FreshAgent, {
tabId: 'tab-1',
diff --git a/test/unit/client/components/panes/PaneHeader.test.tsx b/test/unit/client/components/panes/PaneHeader.test.tsx
index cbb912c38..30ec2ff62 100644
--- a/test/unit/client/components/panes/PaneHeader.test.tsx
+++ b/test/unit/client/components/panes/PaneHeader.test.tsx
@@ -137,6 +137,25 @@ describe('PaneHeader', () => {
expect(screen.getByText('My Terminal')).toBeInTheDocument()
})
+ it('renders its pane-header context marker and exact pane identity', () => {
+ render(
+
+ )
+
+ const header = screen.getByRole('banner', { name: 'Pane: My Terminal' })
+ expect(header).toHaveAttribute('data-context', 'pane-header')
+ expect(header).toHaveAttribute('data-tab-id', 'tab-header')
+ expect(header).toHaveAttribute('data-pane-id', 'pane-header')
+ })
+
it('renders status indicator', () => {
render(