Provides a concrete Tmux-based implementation of the Multiplexer interface for managing child session panes within a Tmux session. Handles pane spawning, graceful shutdown, and layout management for OpenCode's multiplexer system.
Implements the Multiplexer interface contract defined in src/multiplexer/types.ts with Tmux-specific semantics:
TmuxMultiplexer class maintains internal state (binary path, layout preferences, pane tracking) but is instantiated per-use-case rather than globallywhich/where to locate tmux executable at runtime with fallback behaviorMultiplexer interface: Defines the contract for pane management across multiplexer backends (tmux, zellij)MultiplexerLayout: Type representing Tmux layout types ('main-vertical', 'main-horizontal', 'tiled', 'even-horizontal', 'even-vertical')PaneResult: Return type for pane operations indicating success/failure and pane identifiers1. isAvailable() → findBinary() → locate tmux executable
├─ Checks platform-specific command (which/where)
├─ Verifies tmux version via tmux -V
└─ Caches result for subsequent calls
2. spawnPane(sessionId, description, serverUrl, directory)
├─ Validates tmux binary availability
├─ Constructs opencode attach command with quoted arguments
├─ Executes: tmux split-window -h -d -P -F '#{pane_id}' <opencode-cmd>
├─ Captures stdout to extract pane_id
├─ Renames pane with description (truncated to 30 chars)
└─ Schedules layout rebalance via scheduleLayout()
3. scheduleLayout() → applyLayout() (debounced 150ms)
├─ Increments layoutGeneration counter
├─ Applies stored layout via tmux select-layout
├─ For main-* layouts: sets main-pane-width/height percentage
└─ Reapplies layout to use new size
1. closePane(paneId)
├─ Sends Ctrl+C to pane: tmux send-keys -t <paneId> 'C-c'
├─ Waits 250ms for graceful shutdown
├─ Executes: tmux kill-pane -t <paneId>
└─ Schedules layout rebalance via scheduleLayout()
1. applyLayout(layout, mainPaneSize)
├─ Cancels pending debounced layout if exists
├─ Increments layoutGeneration
└─ Calls applyLayoutNow() immediately
2. applyLayoutNow(layout, mainPaneSize)
├─ Stores layout and size preferences
├─ Executes: tmux select-layout <layout>
├─ For main-* layouts:
│ ├─ Sets main-pane-width/main-pane-height option
│ └─ Reapplies layout to use new size
└─ Logs success/failure
src/multiplexer/multiplexer-manager.ts - Orchestrates multiplexer sessions and delegates pane operationssrc/index.ts - Plugin initialization wires up multiplexer session handlerssrc/multiplexer/config/schema.ts - Provides MultiplexerLayout type and default valuesprocess.env.TMUXopencode command for attach operationssuccess: false from all operations, logs warningsrc/multiplexer/tmux/index.test.ts - Validates pane spawning, closing, layout application, and binary discoveryNo user-facing configuration required. Tmux binary location and session environment are runtime-detected.
| Scenario | Behavior | Mitigation |
|---|---|---|
| tmux binary not found | Returns success: false, logs warning | Fallback to other multiplexer or graceful degradation |
| Pane spawn fails | Returns success: false, logs error | Session continues without pane |
| Layout application fails | Silently ignored, logs debug | Maintains previous layout |
| Pane already closed | Returns false, logs info | Idempotent operation |
| Ctrl+C send fails | Proceeds to kill-pane | Ensures pane termination |
src/multiplexer/types.ts - Multiplexer interface definitionsrc/multiplexer/config/schema.ts - Layout type definitionssrc/multiplexer/multiplexer-manager.ts - Session management integrationsrc/utils/compat.ts - Cross-platform process executionsrc/utils/logger.ts - Logging infrastructure