From c4c1d76fec972e5d902a669f0cb1953eaa528f16 Mon Sep 17 00:00:00 2001 From: Adam Malczewski Date: Thu, 15 Oct 2026 14:38:50 +0900 Subject: feat(tabs): 2-column tab grid with nestable subagent groups + tab menu (add/remove from group) --- src/features/tabs/tabs.ts | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) (limited to 'src/features/tabs/tabs.ts') diff --git a/src/features/tabs/tabs.ts b/src/features/tabs/tabs.ts index ff7bb4f..b2dad7d 100644 --- a/src/features/tabs/tabs.ts +++ b/src/features/tabs/tabs.ts @@ -13,6 +13,13 @@ export interface Tab { * renamed/removed. Absent for a raw model selection. */ readonly snapshot?: NamedAgentSelectionSnapshot; + /** + * The EFFECTIVE tab group parent (backend `tabGroupParentId`): the + * conversation whose subagent group this tab is visually nested under in + * the tab grid. Purely presentational — distinct from the lineage + * `parentConversationId`. Absent = ungrouped (a top-level tab). + */ + readonly tabGroupParentId?: string; } export interface TabsState { @@ -120,6 +127,26 @@ export function setTitle(state: TabsState, conversationId: string, title: string return { tabs, activeConversationId: state.activeConversationId }; } +/** + * Set (string) or clear (null) a tab's tab group parent. Omits the key when + * cleared (`exactOptionalPropertyTypes`). No-op for an unknown tab. + */ +export function setTabGroupParent( + state: TabsState, + conversationId: string, + parentId: string | null, +): TabsState { + const tabs = state.tabs.map((t) => { + if (t.conversationId !== conversationId) return t; + if (parentId !== null) return { ...t, tabGroupParentId: parentId }; + if (!("tabGroupParentId" in t)) return t; + const { tabGroupParentId: _omit, ...rest } = t; + void _omit; + return rest; + }); + return { tabs, activeConversationId: state.activeConversationId }; +} + export function setWorkspaceId( state: TabsState, conversationId: string, -- cgit v1.2.3