@humanu/orchestra 0.5.75 → 0.5.77

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@humanu/orchestra",
3
- "version": "0.5.75",
3
+ "version": "0.5.77",
4
4
  "description": "AI-powered Git worktree and tmux session manager with modern TUI",
5
5
  "keywords": [
6
6
  "git",
@@ -506,9 +506,18 @@ _tmux_truncate_tab_label() {
506
506
  fi
507
507
  }
508
508
 
509
+ _tmux_pad_menu_label() {
510
+ local label="$1"
511
+ local width="${2:-56}"
512
+
513
+ label="$(_tmux_truncate_tab_label "$label" "$width")"
514
+ printf '%-*s' "$width" "$label"
515
+ }
516
+
509
517
  _tmux_workspace_session_rows() {
510
518
  local current_session="$1"
511
519
  local repo_root="$2"
520
+ local mode="${3:-visible}"
512
521
  local db_path active_file
513
522
  db_path="$(_tmux_session_registry_path)"
514
523
 
@@ -521,11 +530,11 @@ _tmux_workspace_session_rows() {
521
530
  return 0
522
531
  }
523
532
 
524
- python3 - "$db_path" "$repo_root" "$current_session" "$active_file" <<'PY'
533
+ python3 - "$db_path" "$repo_root" "$current_session" "$active_file" "$mode" <<'PY'
525
534
  import sqlite3
526
535
  import sys
527
536
 
528
- db_path, repo_root, current_session, active_path = sys.argv[1:5]
537
+ db_path, repo_root, current_session, active_path, mode = sys.argv[1:6]
529
538
  with open(active_path, "r", encoding="utf-8") as handle:
530
539
  active = {line.strip() for line in handle if line.strip()}
531
540
 
@@ -551,7 +560,7 @@ if not filtered:
551
560
  raise SystemExit(0)
552
561
 
553
562
  max_tabs = 8
554
- if len(filtered) <= max_tabs:
563
+ if mode == "all" or len(filtered) <= max_tabs:
555
564
  visible = filtered
556
565
  prefix = suffix = False
557
566
  else:
@@ -636,10 +645,21 @@ _tmux_workspace_session_tabs() {
636
645
  printf '%s' "$tabs"
637
646
  }
638
647
 
648
+ _tmux_current_session_label() {
649
+ local session_display_name="$1"
650
+ local label escaped_label
651
+
652
+ label="$(_tmux_truncate_tab_label "$session_display_name" 28)"
653
+ escaped_label="$(_tmux_status_escape_text "$label")"
654
+ printf '#[fg=#7aa2f7,bg=#1a1b26,bold] %s #[fg=#565f89,bg=#1a1b26,nobold]│#[default]' "$escaped_label"
655
+ }
656
+
639
657
  _tmux_orchestra_status_left() {
640
658
  local session_name="$1"
641
659
  local session_display_name="$3"
642
- _tmux_workspace_session_tabs "$session_name" "$session_display_name"
660
+ printf '%s%s' \
661
+ "$(_tmux_current_session_label "$session_display_name")" \
662
+ "$(_tmux_workspace_session_tabs "$session_name" "$session_display_name")"
643
663
  }
644
664
 
645
665
  _tmux_orchestra_status_right() {
@@ -651,14 +671,17 @@ _tmux_configure_orchestra_bindings() {
651
671
  bridge="$(_orchestra_bridge_script)"
652
672
  [[ -f "$bridge" ]] || return
653
673
 
654
- local quoted_bridge rename_command prompt_command next_command previous_command new_session_command help_command
674
+ local quoted_bridge rename_command prompt_command next_command previous_command new_session_command list_command close_command close_prompt_command help_command
655
675
  printf -v quoted_bridge '%q' "$bridge"
656
676
  rename_command="$quoted_bridge manual-rename-session \\\"#{session_name}\\\" \\\"%%\\\" >/dev/null 2>&1"
657
677
  prompt_command="command-prompt -p 'Rename Orchestra session:' 'run-shell -b \"$rename_command\"'"
658
678
  next_command="$quoted_bridge cycle-workspace-session \\\"#{session_name}\\\" next \\\"#{client_tty}\\\" >/dev/null 2>&1"
659
679
  previous_command="$quoted_bridge cycle-workspace-session \\\"#{session_name}\\\" previous \\\"#{client_tty}\\\" >/dev/null 2>&1"
660
- new_session_command="$quoted_bridge create-workspace-session \\\"#{session_name}\\\" \\\"#{client_tty}\\\" >/dev/null 2>&1"
661
- help_command="$quoted_bridge tmux-help-popup \\\"#{client_tty}\\\" >/dev/null 2>&1"
680
+ new_session_command="$quoted_bridge create-workspace-session \\\"#{session_name}\\\" \\\"#{client_tty}\\\" >/dev/null 2>&1 || true"
681
+ list_command="$quoted_bridge workspace-session-menu \\\"#{session_name}\\\" \\\"#{client_tty}\\\" >/dev/null 2>&1 || true"
682
+ close_command="$quoted_bridge close-workspace-session \\\"#{session_name}\\\" \\\"#{client_tty}\\\" >/dev/null 2>&1 || true"
683
+ close_prompt_command="confirm-before -p 'Close current Orchestra session? (y/n)' 'run-shell -b \"$close_command\"'"
684
+ help_command="$quoted_bridge tmux-help-popup \\\"#{client_tty}\\\" >/dev/null 2>&1 || true"
662
685
 
663
686
  tmux bind-key -T prefix '?' if-shell -F '#{@orchestra_display_name}' \
664
687
  "run-shell -b \"$help_command\"" 'list-keys -N' >/dev/null 2>&1 || true
@@ -666,6 +689,12 @@ _tmux_configure_orchestra_bindings() {
666
689
  "run-shell -b \"$help_command\"" 'refresh-client -S' >/dev/null 2>&1 || true
667
690
  tmux bind-key -T prefix n if-shell -F '#{@orchestra_display_name}' \
668
691
  "run-shell -b \"$new_session_command\"" 'next-window' >/dev/null 2>&1 || true
692
+ tmux bind-key -T prefix l if-shell -F '#{@orchestra_display_name}' \
693
+ "run-shell -b \"$list_command\"" 'last-window' >/dev/null 2>&1 || true
694
+ tmux bind-key -T prefix q if-shell -F '#{@orchestra_display_name}' \
695
+ "$close_prompt_command" 'display-panes' >/dev/null 2>&1 || true
696
+ tmux bind-key -T prefix X if-shell -F '#{@orchestra_display_name}' \
697
+ "$close_prompt_command" 'confirm-before -p "kill-session #S? (y/n)" kill-session' >/dev/null 2>&1 || true
669
698
  tmux bind-key -T prefix r if-shell -F '#{@orchestra_display_name}' \
670
699
  "$prompt_command" 'refresh-client -S' >/dev/null 2>&1 || true
671
700
  tmux bind-key -T prefix '>' if-shell -F '#{@orchestra_display_name}' \
@@ -944,6 +973,37 @@ tmux_create_workspace_session() {
944
973
  printf '%s\n' "$new_session"
945
974
  }
946
975
 
976
+ # Close the current Orchestra session after switching the client to the next one.
977
+ # Usage: tmux_close_workspace_session <current_session> [client_tty]
978
+ tmux_close_workspace_session() {
979
+ local current_session="$1"
980
+ local target_client="${2:-}"
981
+ local target_session
982
+
983
+ if ! tmux_available; then
984
+ err "tmux not installed"
985
+ return 1
986
+ fi
987
+ if [[ -z "$current_session" ]]; then
988
+ err "tmux_close_workspace_session: current session required"
989
+ return 1
990
+ fi
991
+
992
+ if ! target_session="$(tmux_workspace_cycle_target "$current_session" next)"; then
993
+ tmux display-message -d 2500 "No other Orchestra sessions; current session kept" 2>/dev/null || true
994
+ return 1
995
+ fi
996
+
997
+ if [[ -n "$target_client" ]]; then
998
+ tmux switch-client -c "$target_client" -t "$target_session" >/dev/null 2>&1 || return 1
999
+ else
1000
+ tmux switch-client -t "$target_session" >/dev/null 2>&1 || return 1
1001
+ fi
1002
+
1003
+ tmux_kill_session "$current_session" >/dev/null 2>&1 || return 1
1004
+ _tmux_refresh_orchestra_session_status "$target_session" >/dev/null 2>&1 || true
1005
+ }
1006
+
947
1007
  # Check if a session exists
948
1008
  # Usage: tmux_session_exists <session_name>
949
1009
  tmux_session_exists() {
@@ -1556,6 +1616,8 @@ printf "%s\n" \
1556
1616
  "Ctrl+b, d Detach and return to Orchestra" \
1557
1617
  "Ctrl+b, r Rename the current Orchestra session" \
1558
1618
  "Ctrl+b, n New Orchestra session in this worktree" \
1619
+ "Ctrl+b, q Close current session and switch next" \
1620
+ "Ctrl+b, l List active sessions" \
1559
1621
  "" \
1560
1622
  "Ctrl+b, Left Previous Orchestra session in this workspace" \
1561
1623
  "Ctrl+b, Right Next Orchestra session in this workspace" \
@@ -1573,7 +1635,89 @@ exit 0
1573
1635
  EOF
1574
1636
  )"
1575
1637
 
1576
- tmux display-popup "${target_args[@]}" -E -w 78 -h 18 -T "Orchestra shortcuts" "$popup_command" >/dev/null 2>&1 || true
1638
+ tmux display-popup "${target_args[@]}" \
1639
+ -E \
1640
+ -w 84 \
1641
+ -h 22 \
1642
+ -s "fg=#c0caf5,bg=#1a1b26" \
1643
+ -S "fg=#7aa2f7,bg=#1a1b26" \
1644
+ -T "Orchestra shortcuts" \
1645
+ "$popup_command" >/dev/null 2>&1 || true
1646
+ }
1647
+
1648
+ # Show active Orchestra sessions in a native tmux menu for arrow-key selection.
1649
+ # Usage: tmux_show_workspace_session_menu <current_session> [client_tty]
1650
+ tmux_show_workspace_session_menu() {
1651
+ local current_session="$1"
1652
+ local target_client="${2:-}"
1653
+ local session_dir repo_root rows name display_name label target_command
1654
+ local menu_width=56
1655
+ local min_menu_rows=10
1656
+ local menu_row_count=0
1657
+
1658
+ if ! tmux_available; then
1659
+ err "tmux not installed"
1660
+ return 1
1661
+ fi
1662
+ if [[ -z "$current_session" ]]; then
1663
+ err "tmux_show_workspace_session_menu: current session required"
1664
+ return 1
1665
+ fi
1666
+
1667
+ session_dir="$(tmux display-message -t "$current_session" -p '#{pane_current_path}' 2>/dev/null || echo "")"
1668
+ repo_root="$(_tmux_shared_root_for_path "$session_dir" 2>/dev/null || true)"
1669
+ if [[ -z "$repo_root" ]]; then
1670
+ tmux display-message -d 2500 "Unable to determine Orchestra workspace" 2>/dev/null || true
1671
+ return 1
1672
+ fi
1673
+
1674
+ _tmux_registry_sync_active_workspace_sessions "$repo_root" >/dev/null 2>&1 || true
1675
+ rows="$(_tmux_workspace_session_rows "$current_session" "$repo_root" all 2>/dev/null || true)"
1676
+ if [[ -z "$rows" ]]; then
1677
+ tmux display-message -d 2500 "No active Orchestra sessions in this workspace" 2>/dev/null || true
1678
+ return 1
1679
+ fi
1680
+
1681
+ local target_args=()
1682
+ if [[ -n "$target_client" ]]; then
1683
+ target_args=(-c "$target_client")
1684
+ fi
1685
+
1686
+ local menu_items=()
1687
+ while IFS=$'\t' read -r name display_name; do
1688
+ [[ -n "$name" && "$name" != "__ellipsis__" ]] || continue
1689
+ if [[ -z "$display_name" ]]; then
1690
+ display_name="$(tmux_format_session_display "$name" without-timestamp)"
1691
+ fi
1692
+ label="$(_tmux_truncate_tab_label "$display_name" 42)"
1693
+ if [[ "$name" == "$current_session" ]]; then
1694
+ label="● $label"
1695
+ else
1696
+ label=" $label"
1697
+ fi
1698
+ label="$(_tmux_pad_menu_label "$label" "$menu_width")"
1699
+ label="$(_tmux_status_escape_text "$label")"
1700
+ target_command="switch-client -t \"$name\""
1701
+ menu_items+=("$label" "" "$target_command")
1702
+ menu_row_count=$((menu_row_count + 1))
1703
+ done <<< "$rows"
1704
+
1705
+ if [[ ${#menu_items[@]} -eq 0 ]]; then
1706
+ tmux display-message -d 2500 "No active Orchestra sessions in this workspace" 2>/dev/null || true
1707
+ return 1
1708
+ fi
1709
+
1710
+ while (( menu_row_count < min_menu_rows )); do
1711
+ menu_items+=("$(_tmux_pad_menu_label "" "$menu_width")" "" "")
1712
+ menu_row_count=$((menu_row_count + 1))
1713
+ done
1714
+
1715
+ tmux display-menu "${target_args[@]}" \
1716
+ -s "fg=#c0caf5,bg=#1a1b26" \
1717
+ -S "fg=#7aa2f7,bg=#1a1b26" \
1718
+ -H "fg=#1a1b26,bg=#ff9e64,bold" \
1719
+ -T "Orchestra sessions" \
1720
+ "${menu_items[@]}" >/dev/null 2>&1 || true
1577
1721
  }
1578
1722
 
1579
1723
  # Find the adjacent active Orchestra session registered for the current repo.
@@ -102,6 +102,14 @@ case "${1:-}" in
102
102
  bridge_create_workspace_session "${2:-}" "${3:-}"
103
103
  ;;
104
104
 
105
+ "close-workspace-session")
106
+ bridge_close_workspace_session "${2:-}" "${3:-}"
107
+ ;;
108
+
109
+ "workspace-session-menu")
110
+ bridge_workspace_session_menu "${2:-}" "${3:-}"
111
+ ;;
112
+
105
113
  "kill-session")
106
114
  bridge_kill_session "${2:-}"
107
115
  ;;
@@ -249,6 +257,10 @@ Commands:
249
257
  Switch within registered Orchestra sessions for this repo
250
258
  create-workspace-session <session> [client]
251
259
  Create a new session in the current worktree and switch to it
260
+ close-workspace-session <session> [client]
261
+ Close current session after switching to the next one
262
+ workspace-session-menu <session> [client]
263
+ Show an interactive active-session menu
252
264
  tmux-help-popup [client] Show Orchestra tmux shortcut popup
253
265
  repo-info Get repository information
254
266
  git-status Get git status --porcelain
@@ -82,6 +82,46 @@ bridge_create_workspace_session() {
82
82
  fi
83
83
  }
84
84
 
85
+ # Close current tmux session after switching to the next workspace session.
86
+ bridge_close_workspace_session() {
87
+ if [[ -z "${1:-}" ]]; then
88
+ json_error "Current session name required"
89
+ return 1
90
+ fi
91
+ session_name="$1"
92
+ target_client="${2:-}"
93
+
94
+ if tmux_available; then
95
+ tmux_close_workspace_session "$session_name" "$target_client" || {
96
+ json_error "Failed to close workspace session"
97
+ return 1
98
+ }
99
+ json_object "ok:b=true"
100
+ else
101
+ json_error "tmux not available"
102
+ fi
103
+ }
104
+
105
+ # Show interactive workspace session menu.
106
+ bridge_workspace_session_menu() {
107
+ if [[ -z "${1:-}" ]]; then
108
+ json_error "Current session name required"
109
+ return 1
110
+ fi
111
+ session_name="$1"
112
+ target_client="${2:-}"
113
+
114
+ if tmux_available; then
115
+ tmux_show_workspace_session_menu "$session_name" "$target_client" || {
116
+ json_error "Failed to show workspace session menu"
117
+ return 1
118
+ }
119
+ json_object "ok:b=true"
120
+ else
121
+ json_error "tmux not available"
122
+ fi
123
+ }
124
+
85
125
  # Kill tmux session
86
126
  bridge_kill_session() {
87
127
  if [[ -z "${1:-}" ]]; then