ITADN

Feature Request: Export standalone shell script from config

#329Openjtnats 创建于 2026-02-11
enhancement
J
jtnatscommented
## 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` &rarr; `tmux new-session -d -s ...` - `new_window` / `rename_window` &rarr; `tmux new-window ...` / `tmux rename-window ...` - `split_window` &rarr; `tmux split-window ...` with shell variable capture - `select_custom_layout` &rarr; `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 条评论