Feature Request: Export standalone shell script from config
enhancement
## Summary
**Disclaimer:** *This issue content was drafted with assistance from Claude Opus. The codebase analysis, feasibility assessment, and implementation plan were produced collaboratively between a human and AI.*
Add a command (e.g. `laio session export` or `laio export`) that reads a laio YAML config file and emits a self-contained bash script that recreates the same tmux session, windows, panes, layout, and commands — without requiring the `laio` binary.
## Motivation
Laio configs are a great way to define reproducible tmux workspaces, but sharing them currently requires the recipient to have laio installed. In many real-world scenarios — customer environments, CI runners, minimal Linux boxes — only `bash` and `tmux` are available.
A generated standalone script would let users:
- Share preconfigured tmux environments with customers or teammates who don't have laio
- Use laio as a **development-time** tool for authoring layouts, then distribute a plain script for **runtime**
- Embed tmux workspace setup in provisioning or onboarding scripts with zero extra dependencies
### Example
Given a config like `nats-pane-demo.yaml`:
```yaml
name: nats-pane-demo
path: ~/
windows:
- name: nats
flex_direction: column
panes:
- name: nats-server
flex: 60
commands:
- command: nats-server
- flex_direction: row
flex: 40
panes:
- name: sub
flex: 1
commands:
- command: nats
args: [sub, test]
- name: one
flex: 1
commands:
- command: nats
args: [pub, test, one]
- name: two
flex: 1
commands:
- command: nats
args: [pub, test, two]
```
Running `laio session export --file nats-pane-demo.yaml` would produce a script roughly like:
```bash
#!/usr/bin/env bash
set -euo pipefail
SESSION="nats-pane-demo"
# Exit early if session already exists
tmux has-session -t "$SESSION" 2>/dev/null && { tmux attach-session -t "$SESSION"; exit 0; }
# Create session
tmux new-session -d -s "$SESSION" -c "$HOME"
# Window: nats
WINDOW_ID=$(tmux display-message -t "$SESSION" -p "#I")
tmux rename-window -t "$SESSION:$WINDOW_ID" "nats"
# Create panes
PANE0=$(tmux display-message -t "$SESSION:$WINDOW_ID" -p "#{pane_id}")
tmux select-pane -t "$SESSION:$WINDOW_ID.$PANE0" -T "nats-server"
PANE1=$(tmux split-window -t "$SESSION:$WINDOW_ID" -c "$HOME" -P -F "#{pane_id}")
tmux select-pane -t "$PANE1" -T "sub"
PANE2=$(tmux split-window -t "$SESSION:$WINDOW_ID" -c "$HOME" -P -F "#{pane_id}")
tmux select-pane -t "$PANE2" -T "one"
PANE3=$(tmux split-window -t "$SESSION:$WINDOW_ID" -c "$HOME" -P -F "#{pane_id}")
tmux select-pane -t "$PANE3" -T "two"
# Apply layout
tmux select-layout -t "$SESSION:$WINDOW_ID" "<checksum>,<computed-layout-string>"
# Send commands
tmux send-keys -t "$PANE0" "nats-server" C-m
tmux send-keys -t "$PANE1" "nats sub test" C-m
tmux send-keys -t "$PANE2" "nats pub test one" C-m
tmux send-keys -t "$PANE3" "nats pub test two" C-m
# Attach
tmux attach-session -t "$SESSION"
```
## Scope
The export should support the core config features:
- [x] Session name, path, and environment variables
- [x] Multiple windows with names
- [x] Nested panes with flex-based layout (the computed tmux layout string)
- [x] Pane names, paths, styles, zoom, and focus
- [x] Commands and inline scripts per pane
- [x] Startup and shutdown commands/scripts
- [x] Custom shell override
Nice-to-have (could be follow-up):
- [ ] Dynamic terminal size detection via `tput cols` / `tput lines` (vs. a fixed default)
- [ ] Optional `--output <file>` flag to write directly to a file instead of stdout
---
## Implementation Plan
### 1. New CLI subcommand
Add an `Export` variant to the session CLI commands in `src/app/cli/session/cli.rs`:
```
laio session export --file <config.yaml> [--muxer tmux]
```
This parses the YAML into a `Session` struct (reusing the existing config model) and passes it to a new export function.
### 2. Script generator module
Create a new module (e.g. `src/muxer/tmux/export.rs`) that takes a `Session` and terminal `Dimensions` and returns a `String` containing the complete bash script.
The generator walks the `Session` struct in the same order as `Tmux::start()` / `Tmux::process_windows()`, but instead of calling `TmuxClient` methods, it appends the equivalent shell commands to a buffer:
- `create_session` → `tmux new-session -d -s ...`
- `new_window` / `rename_window` → `tmux new-window ...` / `tmux rename-window ...`
- `split_window` → `tmux split-window ...` with shell variable capture
- `select_custom_layout` → `tmux select-layout ...` with precomputed layout string
- `send-keys` for commands, `select-pane -T` for titles, etc.
### 3. Layout computation
The existing `generate_layout` method in `mux.rs` interleaves layout string computation with live tmux calls (to create panes and retrieve their IDs). For export, one of two approaches:
- **Option A (preferred):** Refactor `generate_layout` into a two-phase process — first compute the layout tree with synthetic pane IDs, then either execute live or emit script. This avoids code duplication.
- **Option B:** Duplicate the layout walk in the export module, assigning sequential pane IDs and building the layout string without calling tmux.
The layout checksum function (`layout_checksum` in `client.rs`) is pure and can be called directly at export time.
### 4. Terminal dimensions
The layout string requires concrete dimensions. Options:
- Use a sensible default (e.g. 200x50) with a `--size WxH` flag to override
- Emit a small shell preamble that queries `tput cols` / `tput lines` — though this adds complexity since the layout string must be precomputed
A fixed default with an override flag is the simplest starting point.
### 5. Testing
- Unit tests: given a `Session` struct, assert the generated script contains the expected tmux commands in order
- Integration: run a generated script in a tmux environment and verify the session layout matches the original config
3 条评论