@humanu/orchestra 0.5.75 → 0.5.76

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.76",
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:
@@ -651,14 +660,17 @@ _tmux_configure_orchestra_bindings() {
651
660
  bridge="$(_orchestra_bridge_script)"
652
661
  [[ -f "$bridge" ]] || return
653
662
 
654
- local quoted_bridge rename_command prompt_command next_command previous_command new_session_command help_command
663
+ local quoted_bridge rename_command prompt_command next_command previous_command new_session_command list_command close_command close_prompt_command help_command
655
664
  printf -v quoted_bridge '%q' "$bridge"
656
665
  rename_command="$quoted_bridge manual-rename-session \\\"#{session_name}\\\" \\\"%%\\\" >/dev/null 2>&1"
657
666
  prompt_command="command-prompt -p 'Rename Orchestra session:' 'run-shell -b \"$rename_command\"'"
658
667
  next_command="$quoted_bridge cycle-workspace-session \\\"#{session_name}\\\" next \\\"#{client_tty}\\\" >/dev/null 2>&1"
659
668
  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"
669
+ new_session_command="$quoted_bridge create-workspace-session \\\"#{session_name}\\\" \\\"#{client_tty}\\\" >/dev/null 2>&1 || true"
670
+ list_command="$quoted_bridge workspace-session-menu \\\"#{session_name}\\\" \\\"#{client_tty}\\\" >/dev/null 2>&1 || true"
671
+ close_command="$quoted_bridge close-workspace-session \\\"#{session_name}\\\" \\\"#{client_tty}\\\" >/dev/null 2>&1 || true"
672
+ close_prompt_command="confirm-before -p 'Close current Orchestra session? (y/n)' 'run-shell -b \"$close_command\"'"
673
+ help_command="$quoted_bridge tmux-help-popup \\\"#{client_tty}\\\" >/dev/null 2>&1 || true"
662
674
 
663
675
  tmux bind-key -T prefix '?' if-shell -F '#{@orchestra_display_name}' \
664
676
  "run-shell -b \"$help_command\"" 'list-keys -N' >/dev/null 2>&1 || true
@@ -666,6 +678,10 @@ _tmux_configure_orchestra_bindings() {
666
678
  "run-shell -b \"$help_command\"" 'refresh-client -S' >/dev/null 2>&1 || true
667
679
  tmux bind-key -T prefix n if-shell -F '#{@orchestra_display_name}' \
668
680
  "run-shell -b \"$new_session_command\"" 'next-window' >/dev/null 2>&1 || true
681
+ tmux bind-key -T prefix l if-shell -F '#{@orchestra_display_name}' \
682
+ "run-shell -b \"$list_command\"" 'last-window' >/dev/null 2>&1 || true
683
+ tmux bind-key -T prefix X if-shell -F '#{@orchestra_display_name}' \
684
+ "$close_prompt_command" 'confirm-before -p "kill-session #S? (y/n)" kill-session' >/dev/null 2>&1 || true
669
685
  tmux bind-key -T prefix r if-shell -F '#{@orchestra_display_name}' \
670
686
  "$prompt_command" 'refresh-client -S' >/dev/null 2>&1 || true
671
687
  tmux bind-key -T prefix '>' if-shell -F '#{@orchestra_display_name}' \
@@ -944,6 +960,37 @@ tmux_create_workspace_session() {
944
960
  printf '%s\n' "$new_session"
945
961
  }
946
962
 
963
+ # Close the current Orchestra session after switching the client to the next one.
964
+ # Usage: tmux_close_workspace_session <current_session> [client_tty]
965
+ tmux_close_workspace_session() {
966
+ local current_session="$1"
967
+ local target_client="${2:-}"
968
+ local target_session
969
+
970
+ if ! tmux_available; then
971
+ err "tmux not installed"
972
+ return 1
973
+ fi
974
+ if [[ -z "$current_session" ]]; then
975
+ err "tmux_close_workspace_session: current session required"
976
+ return 1
977
+ fi
978
+
979
+ if ! target_session="$(tmux_workspace_cycle_target "$current_session" next)"; then
980
+ tmux display-message -d 2500 "No other Orchestra sessions; current session kept" 2>/dev/null || true
981
+ return 1
982
+ fi
983
+
984
+ if [[ -n "$target_client" ]]; then
985
+ tmux switch-client -c "$target_client" -t "$target_session" >/dev/null 2>&1 || return 1
986
+ else
987
+ tmux switch-client -t "$target_session" >/dev/null 2>&1 || return 1
988
+ fi
989
+
990
+ tmux_kill_session "$current_session" >/dev/null 2>&1 || return 1
991
+ _tmux_refresh_orchestra_session_status "$target_session" >/dev/null 2>&1 || true
992
+ }
993
+
947
994
  # Check if a session exists
948
995
  # Usage: tmux_session_exists <session_name>
949
996
  tmux_session_exists() {
@@ -1556,6 +1603,8 @@ printf "%s\n" \
1556
1603
  "Ctrl+b, d Detach and return to Orchestra" \
1557
1604
  "Ctrl+b, r Rename the current Orchestra session" \
1558
1605
  "Ctrl+b, n New Orchestra session in this worktree" \
1606
+ "Ctrl+b, X Close current session and switch next" \
1607
+ "Ctrl+b, l List active sessions" \
1559
1608
  "" \
1560
1609
  "Ctrl+b, Left Previous Orchestra session in this workspace" \
1561
1610
  "Ctrl+b, Right Next Orchestra session in this workspace" \
@@ -1573,7 +1622,89 @@ exit 0
1573
1622
  EOF
1574
1623
  )"
1575
1624
 
1576
- tmux display-popup "${target_args[@]}" -E -w 78 -h 18 -T "Orchestra shortcuts" "$popup_command" >/dev/null 2>&1 || true
1625
+ tmux display-popup "${target_args[@]}" \
1626
+ -E \
1627
+ -w 84 \
1628
+ -h 22 \
1629
+ -s "fg=#c0caf5,bg=#1a1b26" \
1630
+ -S "fg=#7aa2f7,bg=#1a1b26" \
1631
+ -T "Orchestra shortcuts" \
1632
+ "$popup_command" >/dev/null 2>&1 || true
1633
+ }
1634
+
1635
+ # Show active Orchestra sessions in a native tmux menu for arrow-key selection.
1636
+ # Usage: tmux_show_workspace_session_menu <current_session> [client_tty]
1637
+ tmux_show_workspace_session_menu() {
1638
+ local current_session="$1"
1639
+ local target_client="${2:-}"
1640
+ local session_dir repo_root rows name display_name label target_command
1641
+ local menu_width=56
1642
+ local min_menu_rows=10
1643
+ local menu_row_count=0
1644
+
1645
+ if ! tmux_available; then
1646
+ err "tmux not installed"
1647
+ return 1
1648
+ fi
1649
+ if [[ -z "$current_session" ]]; then
1650
+ err "tmux_show_workspace_session_menu: current session required"
1651
+ return 1
1652
+ fi
1653
+
1654
+ session_dir="$(tmux display-message -t "$current_session" -p '#{pane_current_path}' 2>/dev/null || echo "")"
1655
+ repo_root="$(_tmux_shared_root_for_path "$session_dir" 2>/dev/null || true)"
1656
+ if [[ -z "$repo_root" ]]; then
1657
+ tmux display-message -d 2500 "Unable to determine Orchestra workspace" 2>/dev/null || true
1658
+ return 1
1659
+ fi
1660
+
1661
+ _tmux_registry_sync_active_workspace_sessions "$repo_root" >/dev/null 2>&1 || true
1662
+ rows="$(_tmux_workspace_session_rows "$current_session" "$repo_root" all 2>/dev/null || true)"
1663
+ if [[ -z "$rows" ]]; then
1664
+ tmux display-message -d 2500 "No active Orchestra sessions in this workspace" 2>/dev/null || true
1665
+ return 1
1666
+ fi
1667
+
1668
+ local target_args=()
1669
+ if [[ -n "$target_client" ]]; then
1670
+ target_args=(-c "$target_client")
1671
+ fi
1672
+
1673
+ local menu_items=()
1674
+ while IFS=$'\t' read -r name display_name; do
1675
+ [[ -n "$name" && "$name" != "__ellipsis__" ]] || continue
1676
+ if [[ -z "$display_name" ]]; then
1677
+ display_name="$(tmux_format_session_display "$name" without-timestamp)"
1678
+ fi
1679
+ label="$(_tmux_truncate_tab_label "$display_name" 42)"
1680
+ if [[ "$name" == "$current_session" ]]; then
1681
+ label="● $label"
1682
+ else
1683
+ label=" $label"
1684
+ fi
1685
+ label="$(_tmux_pad_menu_label "$label" "$menu_width")"
1686
+ label="$(_tmux_status_escape_text "$label")"
1687
+ target_command="switch-client -t \"$name\""
1688
+ menu_items+=("$label" "" "$target_command")
1689
+ menu_row_count=$((menu_row_count + 1))
1690
+ done <<< "$rows"
1691
+
1692
+ if [[ ${#menu_items[@]} -eq 0 ]]; then
1693
+ tmux display-message -d 2500 "No active Orchestra sessions in this workspace" 2>/dev/null || true
1694
+ return 1
1695
+ fi
1696
+
1697
+ while (( menu_row_count < min_menu_rows )); do
1698
+ menu_items+=("$(_tmux_pad_menu_label "" "$menu_width")" "" "")
1699
+ menu_row_count=$((menu_row_count + 1))
1700
+ done
1701
+
1702
+ tmux display-menu "${target_args[@]}" \
1703
+ -s "fg=#c0caf5,bg=#1a1b26" \
1704
+ -S "fg=#7aa2f7,bg=#1a1b26" \
1705
+ -H "fg=#1a1b26,bg=#ff9e64,bold" \
1706
+ -T "Orchestra sessions" \
1707
+ "${menu_items[@]}" >/dev/null 2>&1 || true
1577
1708
  }
1578
1709
 
1579
1710
  # 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