@@ -39,6 +39,8 @@ export function triggerAction(key: string): void {
3939// repeated down the left columns so left/right crossings stay consistent.
4040
4141const AI_TERMINAL_PANEL = 'ai-terminal' ;
42+ const SHELL_PANEL_PREFIX = 'shell:' ;
43+ const SHELL_TOOLBAR_PANEL_PREFIX = 'shell-toolbar:' ;
4244
4345function aiTerminalPanelId ( agentId : string ) : string {
4446 return `${ AI_TERMINAL_PANEL } :${ agentId } ` ;
@@ -58,6 +60,48 @@ function aiTerminalPanels(task: { agentIds: string[] }): string[] {
5860 return task . agentIds . length > 0 ? task . agentIds . map ( aiTerminalPanelId ) : [ AI_TERMINAL_PANEL ] ;
5961}
6062
63+ function shellToolbarPanels ( task : { projectId : string } ) : string [ ] {
64+ const bookmarkCount =
65+ store . projects . find ( ( p ) => p . id === task . projectId ) ?. terminalBookmarks ?. length ?? 0 ;
66+ return Array . from ( { length : 1 + bookmarkCount } , ( _ , i ) => `${ SHELL_TOOLBAR_PANEL_PREFIX } ${ i } ` ) ;
67+ }
68+
69+ function isShellPanel ( panel : string ) : boolean {
70+ return panel . startsWith ( SHELL_PANEL_PREFIX ) ;
71+ }
72+
73+ function isShellToolbarPanel ( panel : string ) : boolean {
74+ return panel . startsWith ( SHELL_TOOLBAR_PANEL_PREFIX ) ;
75+ }
76+
77+ function edgeIndex ( count : number , entryEdge : 'left' | 'right' ) : number {
78+ return entryEdge === 'right' ? 0 : count - 1 ;
79+ }
80+
81+ function pickTargetTerminalFamilyPanel (
82+ current : string ,
83+ targetTask : { shellAgentIds : string [ ] ; projectId : string } ,
84+ entryEdge : 'left' | 'right' ,
85+ ) : string | null {
86+ if ( isAiTerminalPanel ( current ) ) return AI_TERMINAL_PANEL ;
87+
88+ if ( isShellPanel ( current ) ) {
89+ if ( targetTask . shellAgentIds . length > 0 ) {
90+ return `${ SHELL_PANEL_PREFIX } ${ edgeIndex ( targetTask . shellAgentIds . length , entryEdge ) } ` ;
91+ }
92+
93+ const toolbarPanels = shellToolbarPanels ( targetTask ) ;
94+ return toolbarPanels [ edgeIndex ( toolbarPanels . length , entryEdge ) ] ?? null ;
95+ }
96+
97+ if ( isShellToolbarPanel ( current ) ) {
98+ const toolbarPanels = shellToolbarPanels ( targetTask ) ;
99+ return toolbarPanels [ edgeIndex ( toolbarPanels . length , entryEdge ) ] ?? null ;
100+ }
101+
102+ return null ;
103+ }
104+
61105function normalizeTaskPanel ( taskId : string , panel : string ) : string {
62106 if ( panel !== AI_TERMINAL_PANEL ) return panel ;
63107 const task = store . tasks [ taskId ] ;
@@ -78,9 +122,7 @@ function isLeftColumnPanel(panel: string): boolean {
78122function buildGrid ( panelId : string ) : string [ ] [ ] {
79123 const task = store . tasks [ panelId ] ;
80124 if ( task ) {
81- const bookmarkCount =
82- store . projects . find ( ( p ) => p . id === task . projectId ) ?. terminalBookmarks ?. length ?? 0 ;
83- const toolbarCols = Array . from ( { length : 1 + bookmarkCount } , ( _ , i ) => `shell-toolbar:${ i } ` ) ;
125+ const toolbarCols = shellToolbarPanels ( task ) ;
84126 const aiCols = aiTerminalPanels ( task ) ;
85127
86128 if ( store . taskSplitMode [ panelId ] ) {
@@ -433,6 +475,16 @@ export function navigateColumn(direction: 'left' | 'right'): void {
433475 } else if ( ! store . tasks [ targetId ] ) {
434476 focusTaskPanel ( targetId , defaultPanelFor ( targetId ) ) ;
435477 } else {
478+ const semanticTarget = pickTargetTerminalFamilyPanel (
479+ current ,
480+ store . tasks [ targetId ] ,
481+ entryEdge ,
482+ ) ;
483+ if ( semanticTarget ) {
484+ focusTaskPanel ( targetId , semanticTarget ) ;
485+ return ;
486+ }
487+
436488 const targetGrid = buildGrid ( targetId ) ;
437489 const targetPos = findInGrid ( targetGrid , current ) ;
438490 const targetRow = targetPos ? targetPos . row : pos . row ;
0 commit comments