3.6 KiB
Terminal Multi Tabs Implementation Plan
For agentic workers: REQUIRED: Use superpowers:subagent-driven-development (if subagents available) or superpowers:executing-plans to implement this plan. Steps use checkbox (
- [ ]) syntax for tracking.
Goal: Allow the connection list to open multiple terminal tabs for the same connection, with each click creating a fresh terminal session.
Architecture: Keep the existing /terminal workspace and Pinia-driven tab model, but change terminal tab creation from connection-deduplicated to always-new. Add lightweight title numbering so repeated tabs for the same connection remain distinguishable without changing routing or terminal widget lifecycle.
Tech Stack: Vue 3, TypeScript, Pinia, Vue Router, xterm.js, Vite, vue-tsc
File Structure
- Modify:
frontend/src/stores/terminalTabs.ts- Change tab creation semantics and add repeated-title numbering.
- Modify:
frontend/src/views/ConnectionsView.vue- Use the new always-open terminal action from the connection list.
- Verify:
frontend/src/views/TerminalWorkspaceView.vue- Confirm current per-tab widget mounting already supports independent sessions.
- Verify:
frontend/src/layouts/MainLayout.vue- Confirm terminal sidebar tab rendering needs no structure change beyond new titles.
- Reference:
docs/superpowers/specs/2026-03-26-terminal-multi-tabs-design.md- Source of truth for behavior and acceptance criteria.
Task 1: Change Terminal Tabs Store to Always Create New Tabs
Files:
-
Modify:
frontend/src/stores/terminalTabs.ts -
Reference:
frontend/src/stores/sftpTabs.ts -
Step 1: Inspect current tab store behavior
Read frontend/src/stores/terminalTabs.ts and confirm the existing dedup-by-connection behavior.
- Step 2: Add repeated-title generation
Add a helper that counts currently open tabs for the same connectionId and returns:
function getTabTitle(connection: Connection) {
const sameConnectionCount = tabs.value.filter(t => t.connectionId === connection.id).length
if (sameConnectionCount === 0) {
return connection.name
}
return `${connection.name} (${sameConnectionCount + 1})`
}
- Step 3: Replace dedup open logic with always-new creation
Change the open action so it always creates a new TerminalTab and activates it immediately.
- Step 4: Keep activate/close behavior unchanged
Do not change tab activation and close-neighbor behavior except what is necessary to support the new open logic.
Task 2: Wire the Connection List to the New Behavior
Files:
-
Modify:
frontend/src/views/ConnectionsView.vue -
Use:
frontend/src/stores/terminalTabs.ts -
Step 1: Rename the method usage to match semantics
Update openTerminal(conn) to call the new always-open store action.
- Step 2: Preserve routing behavior
Keep router.push('/terminal') unchanged after opening the tab.
Task 3: Verify Integration and Build
Files:
-
Verify:
frontend/src/layouts/MainLayout.vue -
Verify:
frontend/src/views/TerminalWorkspaceView.vue -
Step 1: Confirm sidebar rendering already keys by
tab.id
No structural code changes should be required if repeated tabs render correctly with distinct titles.
- Step 2: Run final frontend build
Run in frontend/:
npm run build
Expected: vue-tsc -b and vite build both pass.
- Step 3: Manual runtime verification
Check:
- Same connection opens multiple terminal tabs.
- Repeated tabs are titled distinctly.
- Each tab remains an independent terminal session.
- Close/switch behavior still works.