Class: Ace::Assign::Molecules::TmuxForkRunner
- Inherits:
-
Object
- Object
- Ace::Assign::Molecules::TmuxForkRunner
- Defined in:
- lib/ace/assign/molecules/tmux_fork_runner.rb
Overview
Minimal tmux integration for forked subtree execution.
Defined Under Namespace
Classes: Result
Constant Summary collapse
- DEFAULT_POLL_INTERVAL =
0.2
Instance Method Summary collapse
- #current_session ⇒ Object
- #current_window ⇒ Object
- #ensure_window(session:, name:, root:) ⇒ Object
- #fork_window_name(base_window) ⇒ Object
-
#initialize(tmux_binary: "tmux") ⇒ TmuxForkRunner
constructor
A new instance of TmuxForkRunner.
- #merge_tmux_metadata(session_meta_file:, session:, window:, pane:) ⇒ Object
- #prepare_pane(session:, window:, root:, keep_existing:) ⇒ Object
- #run_script_in_pane(pane_target:, script_path:) ⇒ Object
- #select_window(session:, window:) ⇒ Object
- #tmux_context? ⇒ Boolean
- #wait_for_completion(status_file:, timeout:) ⇒ Object
Constructor Details
#initialize(tmux_binary: "tmux") ⇒ TmuxForkRunner
Returns a new instance of TmuxForkRunner.
15 16 17 |
# File 'lib/ace/assign/molecules/tmux_fork_runner.rb', line 15 def initialize(tmux_binary: "tmux") @tmux_binary = tmux_binary end |
Instance Method Details
#current_session ⇒ Object
23 24 25 26 27 28 29 30 31 |
# File 'lib/ace/assign/molecules/tmux_fork_runner.rb', line 23 def current_session explicit = ENV["ACE_TMUX_SESSION"].to_s.strip return explicit unless explicit.empty? return nil if ENV["TMUX"].to_s.strip.empty? capture([tmux_binary, "display-message", "-p", "#S"]).stdout rescue nil end |
#current_window ⇒ Object
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
# File 'lib/ace/assign/molecules/tmux_fork_runner.rb', line 33 def current_window explicit = ENV["ACE_ASSIGN_FORK_WINDOW"].to_s.strip return explicit unless explicit.empty? session = ENV["ACE_TMUX_SESSION"].to_s.strip if !session.empty? window = capture([tmux_binary, "display-message", "-t", "#{session}:", "-p", "#W"]).stdout return window unless window.empty? return active_window_name(session) end return nil if ENV["TMUX"].to_s.strip.empty? capture([tmux_binary, "display-message", "-p", "#W"]).stdout rescue nil end |
#ensure_window(session:, name:, root:) ⇒ Object
57 58 59 60 61 62 63 64 |
# File 'lib/ace/assign/molecules/tmux_fork_runner.rb', line 57 def ensure_window(session:, name:, root:) return {created: false, target: "#{session}:#{name}"} if window_exists?(session: session, name: name) result = capture([tmux_binary, "new-window", "-t", "#{session}:", "-n", name, "-c", File.(root)]) raise Error, "Failed to create tmux fork window #{name}: #{result.stderr}" unless result.success? {created: true, target: "#{session}:#{name}"} end |
#fork_window_name(base_window) ⇒ Object
50 51 52 53 54 55 |
# File 'lib/ace/assign/molecules/tmux_fork_runner.rb', line 50 def fork_window_name(base_window) base = base_window.to_s.strip return base if base.end_with?("-fs") "#{base}-fs" end |
#merge_tmux_metadata(session_meta_file:, session:, window:, pane:) ⇒ Object
109 110 111 112 113 114 115 116 117 118 119 120 |
# File 'lib/ace/assign/molecules/tmux_fork_runner.rb', line 109 def (session_meta_file:, session:, window:, pane:) data = if File.exist?() YAML.safe_load_file() || {} else {} end data["launch_mode"] = "tmux" data["tmux_session"] = session data["tmux_window"] = window data["tmux_pane_id"] = pane File.write(, data.to_yaml) end |
#prepare_pane(session:, window:, root:, keep_existing:) ⇒ Object
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 |
# File 'lib/ace/assign/molecules/tmux_fork_runner.rb', line 66 def prepare_pane(session:, window:, root:, keep_existing:) target = "#{session}:#{window}" if keep_existing pane = first_pane(target) set_pane_remain_on_exit(pane) select_layout(target) return pane end result = capture([tmux_binary, "split-window", "-t", target, "-c", File.(root), "-P", "-F", '#{pane_id}']) raise Error, "Failed to create tmux fork pane in #{window}: #{result.stderr}" unless result.success? pane = result.stdout set_pane_remain_on_exit(pane) select_layout(target) pane end |
#run_script_in_pane(pane_target:, script_path:) ⇒ Object
88 89 90 91 |
# File 'lib/ace/assign/molecules/tmux_fork_runner.rb', line 88 def run_script_in_pane(pane_target:, script_path:) command = "bash #{Shellwords.escape(File.(script_path))}" run!([tmux_binary, "send-keys", "-t", pane_target, command, "Enter"], "send tmux fork command") end |
#select_window(session:, window:) ⇒ Object
84 85 86 |
# File 'lib/ace/assign/molecules/tmux_fork_runner.rb', line 84 def select_window(session:, window:) run!([tmux_binary, "select-window", "-t", "#{session}:#{window}"], "select tmux fork window #{window}") end |
#tmux_context? ⇒ Boolean
19 20 21 |
# File 'lib/ace/assign/molecules/tmux_fork_runner.rb', line 19 def tmux_context? !current_session.to_s.strip.empty? end |
#wait_for_completion(status_file:, timeout:) ⇒ Object
93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 |
# File 'lib/ace/assign/molecules/tmux_fork_runner.rb', line 93 def wait_for_completion(status_file:, timeout:) deadline = Process.clock_gettime(Process::CLOCK_MONOTONIC) + timeout.to_i until File.exist?(status_file) if Process.clock_gettime(Process::CLOCK_MONOTONIC) >= deadline raise Error, "Timed out waiting for tmux fork pane to finish (#{File.basename(status_file)})" end sleep(DEFAULT_POLL_INTERVAL) end status = File.read(status_file).strip Integer(status) rescue ArgumentError raise Error, "Invalid tmux fork status file: #{status_file}" end |