Provides a unified abstraction layer for terminal multiplexers (tmux and zellij) to spawn, manage, and close panes for child OpenCode agent sessions. This enables a "multiplexer-assisted" workflow where each child session runs in its own terminal pane, providing better isolation and resource management compared to traditional background processes.
types.ts): Defines the contract for terminal multiplexer implementations with methods for pane lifecycle management and layout application.TmuxMultiplexer: tmux-specific implementation using tmux CLI commandsZellijMultiplexer: zellij-specific implementation using zellij plugin APIsession-manager.ts): Tracks child session lifecycle and coordinates pane operations via event-driven architecture.factory.ts): Creates appropriate multiplexer instance based on configuration and environment detection.export interface Multiplexer {
readonly type: 'tmux' | 'zellij';
isAvailable(): Promise<boolean>;
isInsideSession(): boolean;
spawnPane(sessionId: string, description: string, serverUrl: string, directory: string): Promise<PaneResult>;
closePane(paneId: string): Promise<boolean>;
applyLayout(layout: MultiplexerLayout, mainPaneSize: number): Promise<void>;
}
The session manager uses a shared global state pattern to coordinate across plugin instances:
sessions: Map of active tracked sessions (sessionId → pane metadata)knownSessions: Map of sessions that have been created but may not have active panesspawningSessions: Set of sessions currently being spawned (prevents duplicate spawns)closingSessions: Map of ongoing close operations (prevents race conditions)deferredIdleCloses: Set of sessions that should be closed on idle but have running background jobsThe session manager reacts to OpenCode session events:
session.created: Spawns a new pane for the child sessionsession.status: Handles idle/busy state transitionssession.deleted: Cleans up pane when session is deleted1. OpenCode creates child session → emits 'session.created' event
2. MultiplexerSessionManager.onSessionCreated()
├─ Checks if multiplexer is enabled
├─ Validates event properties (sessionId, parentId)
├─ Checks if session is already tracked or spawning
├─ Records session in knownSessions
├─ Spawns pane via multiplexer.spawnPane()
│ ├─ Validates server is running
│ ├─ Creates new pane with:
│ │ ├─ Command: opencode attach --session-id <sessionId>
│ │ ├─ Working directory: project directory
│ │ └─ Title: session description
│ └─ Returns paneId
├─ Validates pane creation succeeded
├─ Records session in sessions map with pane metadata
└─ Starts polling loop if not already running
3. Multiplexer implementation spawns pane:
├─ Tmux: Uses 'tmux new-window' or 'tmux split-window'
└─ Zellij: Uses zellij plugin API to create new pane
1. Child session becomes idle → emits 'session.idle' or 'session.status' event
2. MultiplexerSessionManager.onSessionStatus()
├─ Checks if session is tracked
├─ If idle:
│ ├─ Checks for running background jobs
│ ├─ If background job running: defers close
│ └─ Otherwise: closes pane via multiplexer.closePane()
│ ├─ Removes from sessions map
│ ├─ Calls tmux/zellij kill-pane command
│ └─ Logs completion
└─ If busy: respawns pane (same flow as creation)
3. Session deleted → emits 'session.deleted' event
4. MultiplexerSessionManager.onSessionDeleted()
├─ Removes from knownSessions
└─ Closes pane (same flow as idle)
POLL_INTERVAL_BACKGROUND_MS (default: 5000ms)src/index.ts): Initializes multiplexer session manager during plugin startupsrc/council/council-manager.ts): Uses session manager for child session pane managementsrc/utils/background-job-board.ts): Coordinates with session manager to defer pane closing when background jobs are runningsrc/config/schema.ts): Provides MultiplexerConfig with type, layout, and size settingssrc/utils/logger.ts): Logs multiplexer operations for debugginginterface MultiplexerConfig {
type: 'tmux' | 'zellij' | 'auto' | 'none';
layout: MultiplexerLayout; // 'tiled' | 'main-horizontal' | 'main-vertical' | 'grid'
main_pane_size?: number; // Percentage for main pane (0-100)
zellij_pane_mode?: string; // Zellij-specific pane mode
}
TMUX or ZELLIJ)tmux CLI commands via spawn() utilitytmux select-layout and tmux resize-panezellij CLIfactory.test.ts): Validates multiplexer creation and configurationsession-manager.test.ts): Tests event handling and pane lifecycle| File | Purpose |
|---|---|
index.ts |
Public API exports |
types.ts |
Core interfaces and shared utilities |
factory.ts |
Multiplexer instance creation |
session-manager.ts |
Session lifecycle management |
tmux.ts |
tmux-specific implementation |
zellij.ts |
zellij-specific implementation |