@humanu/orchestra 0.5.72 → 0.5.73

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.72",
3
+ "version": "0.5.73",
4
4
  "description": "AI-powered Git worktree and tmux session manager with modern TUI",
5
5
  "keywords": [
6
6
  "git",
@@ -416,6 +416,80 @@ _tmux_registry_sync_active_workspace_sessions() {
416
416
  done < <(tmux list-sessions -F '#{session_name}' 2>/dev/null || true)
417
417
  }
418
418
 
419
+ _tmux_workspace_cycle_target_cached() {
420
+ local current_session="$1"
421
+ local direction="$2"
422
+ local db_path="$3"
423
+ local active_file="$4"
424
+
425
+ python3 - "$db_path" "$current_session" "$direction" "$active_file" <<'PY'
426
+ import sqlite3
427
+ import sys
428
+
429
+ db_path, current_session, direction, active_path = sys.argv[1:5]
430
+ active = set()
431
+ active_orchestra = set()
432
+ with open(active_path, "r", encoding="utf-8") as handle:
433
+ for raw_line in handle:
434
+ line = raw_line.rstrip("\n")
435
+ if not line:
436
+ continue
437
+ parts = line.split("\t", 1)
438
+ name = parts[0].strip()
439
+ display_name = parts[1].strip() if len(parts) > 1 else ""
440
+ if not name:
441
+ continue
442
+ active.add(name)
443
+ if display_name:
444
+ active_orchestra.add(name)
445
+
446
+ try:
447
+ conn = sqlite3.connect(db_path)
448
+ current_row = conn.execute(
449
+ "SELECT repo_root FROM sessions WHERE tmux_name = ?1",
450
+ (current_session,),
451
+ ).fetchone()
452
+ if current_row is None:
453
+ raise SystemExit(2)
454
+
455
+ registered = {
456
+ name
457
+ for (name,) in conn.execute("SELECT tmux_name FROM sessions").fetchall()
458
+ }
459
+ if active_orchestra.difference(registered):
460
+ raise SystemExit(2)
461
+
462
+ rows = conn.execute(
463
+ """
464
+ SELECT tmux_name
465
+ FROM sessions
466
+ WHERE repo_root = ?1
467
+ ORDER BY worktree_path COLLATE NOCASE, created_at, tmux_name COLLATE NOCASE
468
+ """,
469
+ (current_row[0],),
470
+ ).fetchall()
471
+ except sqlite3.Error:
472
+ raise SystemExit(2)
473
+
474
+ names = []
475
+ seen = set()
476
+ for (name,) in rows:
477
+ if name in active and name not in seen:
478
+ names.append(name)
479
+ seen.add(name)
480
+
481
+ if len(names) < 2 or current_session not in seen:
482
+ raise SystemExit(3)
483
+
484
+ index = names.index(current_session)
485
+ if direction == "next":
486
+ index = (index + 1) % len(names)
487
+ else:
488
+ index = (index - 1) % len(names)
489
+ print(names[index])
490
+ PY
491
+ }
492
+
419
493
  _tmux_status_escape_text() {
420
494
  local text="$1"
421
495
  text="${text//\#/##}"
@@ -424,14 +498,22 @@ _tmux_status_escape_text() {
424
498
 
425
499
  _tmux_truncate_tab_label() {
426
500
  local label="$1"
427
- local max_len="${2:-18}"
501
+ local max_len="${2:-14}"
428
502
  if (( ${#label} > max_len )); then
429
- printf '%s...' "${label:0:$((max_len - 3))}"
503
+ printf '%s' "${label:0:max_len}"
430
504
  else
431
505
  printf '%s' "$label"
432
506
  fi
433
507
  }
434
508
 
509
+ _tmux_pad_tab_label() {
510
+ local label="$1"
511
+ local width="${2:-14}"
512
+
513
+ label="$(_tmux_truncate_tab_label "$label" "$width")"
514
+ printf '%-*s' "$width" "$label"
515
+ }
516
+
435
517
  _tmux_workspace_session_rows() {
436
518
  local current_session="$1"
437
519
  local repo_root="$2"
@@ -506,7 +588,9 @@ PY
506
588
  _tmux_workspace_session_tabs() {
507
589
  local current_session="$1"
508
590
  local fallback_display_name="$2"
509
- local session_dir repo_root rows tabs name display_name label escaped_label divider
591
+ local session_dir repo_root rows tabs name display_name tab_label escaped_tab_label divider active_style inactive_style muted_style reset_style
592
+ local tab_width=21
593
+ local active_label_width=19
510
594
 
511
595
  session_dir="$(tmux display-message -t "$current_session" -p '#{pane_current_path}' 2>/dev/null || echo "")"
512
596
  repo_root="$(_tmux_shared_root_for_path "$session_dir" 2>/dev/null || true)"
@@ -518,34 +602,42 @@ _tmux_workspace_session_tabs() {
518
602
  fi
519
603
 
520
604
  if [[ -z "$rows" ]]; then
521
- label="$(_tmux_truncate_tab_label "$fallback_display_name")"
522
- escaped_label="$(_tmux_status_escape_text "$label")"
523
- printf '#[fg=white,bg=colour22,bold] %s #[default]' "$escaped_label"
605
+ tab_label="$(_tmux_pad_tab_label "$fallback_display_name" "$active_label_width")"
606
+ escaped_tab_label="$(_tmux_status_escape_text "$tab_label")"
607
+ printf '#[bg=#414868] #[fg=#ff9e64,bg=#414868,bold] #[fg=#c0caf5,bg=#414868,bold]%s #[default]' "$escaped_tab_label"
524
608
  return
525
609
  fi
526
610
 
611
+ # Tokyo Night palette: midnight footer, muted inactive tabs, orange active marker.
612
+ active_style="#[fg=#c0caf5,bg=#414868,bold]"
613
+ inactive_style="#[fg=#a9b1d6,bg=#24283b,nobold]"
614
+ muted_style="#[fg=#565f89,bg=#1a1b26,nobold]"
615
+ reset_style="#[default]"
527
616
  tabs=""
528
- divider="#[fg=white,bg=colour22] | #[default]"
617
+ divider="${muted_style}|${reset_style}"
529
618
  while IFS=$'\t' read -r name display_name; do
530
619
  [[ -n "$name" ]] || continue
531
620
  if [[ -n "$tabs" ]]; then
532
621
  tabs+="$divider"
533
622
  fi
534
623
  if [[ "$name" == "__ellipsis__" ]]; then
535
- tabs+="#[fg=white,bg=colour22] ... #[default]"
624
+ tab_label="$(_tmux_pad_tab_label "⋯" "$tab_width")"
625
+ escaped_tab_label="$(_tmux_status_escape_text "$tab_label")"
626
+ tabs+="${muted_style} ${escaped_tab_label} ${reset_style}"
536
627
  continue
537
628
  fi
538
629
 
539
630
  if [[ -z "$display_name" ]]; then
540
631
  display_name="$(tmux_format_session_display "$name" without-timestamp)"
541
632
  fi
542
- label="$(_tmux_truncate_tab_label "$display_name")"
543
- escaped_label="$(_tmux_status_escape_text "$label")"
544
-
545
633
  if [[ "$name" == "$current_session" ]]; then
546
- tabs+="#[fg=white,bg=colour22,bold] [${escaped_label}] #[default]"
634
+ tab_label="$(_tmux_pad_tab_label "$display_name" "$active_label_width")"
635
+ escaped_tab_label="$(_tmux_status_escape_text "$tab_label")"
636
+ tabs+="#[bg=#414868] #[fg=#ff9e64,bg=#414868,bold]● ${active_style}${escaped_tab_label} ${reset_style}"
547
637
  else
548
- tabs+="#[fg=white,bg=colour22] ${escaped_label} #[default]"
638
+ tab_label="$(_tmux_pad_tab_label "$display_name" "$tab_width")"
639
+ escaped_tab_label="$(_tmux_status_escape_text "$tab_label")"
640
+ tabs+="${inactive_style} ${escaped_tab_label} ${reset_style}"
549
641
  fi
550
642
  done <<< "$rows"
551
643
 
@@ -604,6 +696,7 @@ _tmux_configure_orchestra_status() {
604
696
  tmux set-option -t "$session_name" @orchestra_worktree_name "$worktree_name" >/dev/null 2>&1 || true
605
697
  tmux set-option -t "$session_name" status on >/dev/null 2>&1 || true
606
698
  tmux set-option -t "$session_name" status-position bottom >/dev/null 2>&1 || true
699
+ tmux set-option -t "$session_name" status-style "fg=#c0caf5,bg=#1a1b26" >/dev/null 2>&1 || true
607
700
  tmux set-option -t "$session_name" status-left "$status_left" >/dev/null 2>&1 || true
608
701
  tmux set-option -t "$session_name" status-left-length 1000 >/dev/null 2>&1 || true
609
702
  tmux set-option -t "$session_name" status-right "$status_right" >/dev/null 2>&1 || true
@@ -1438,7 +1531,7 @@ tmux_show_orchestra_help_popup() {
1438
1531
  tmux_workspace_cycle_target() {
1439
1532
  local current_session="$1"
1440
1533
  local direction="$2"
1441
- local session_dir repo_root db_path active_file target
1534
+ local session_dir repo_root db_path active_file target query_status
1442
1535
 
1443
1536
  if ! tmux_available; then
1444
1537
  err "tmux not installed"
@@ -1456,40 +1549,64 @@ tmux_workspace_cycle_target() {
1456
1549
  ;;
1457
1550
  esac
1458
1551
 
1552
+ db_path="$(_tmux_session_registry_path)"
1553
+ have_cmd python3 || {
1554
+ err "python3 is required to read the Orchestra session registry"
1555
+ return 1
1556
+ }
1557
+
1558
+ active_file="$(mktemp)"
1559
+ tmux list-sessions -F $'#{session_name}\t#{@orchestra_display_name}' > "$active_file" 2>/dev/null || {
1560
+ rm -f "$active_file"
1561
+ err "Unable to list tmux sessions"
1562
+ return 1
1563
+ }
1564
+
1565
+ if [[ -f "$db_path" ]]; then
1566
+ if target="$(_tmux_workspace_cycle_target_cached "$current_session" "$direction" "$db_path" "$active_file")"; then
1567
+ query_status=0
1568
+ else
1569
+ query_status=$?
1570
+ fi
1571
+ if [[ $query_status -eq 0 && -n "$target" ]]; then
1572
+ rm -f "$active_file"
1573
+ printf '%s\n' "$target"
1574
+ return 0
1575
+ fi
1576
+ if [[ $query_status -eq 3 ]]; then
1577
+ rm -f "$active_file"
1578
+ return 1
1579
+ fi
1580
+ fi
1581
+
1459
1582
  _tmux_registry_upsert_current_session "$current_session" >/dev/null 2>&1 || true
1460
1583
 
1461
1584
  session_dir="$(tmux display-message -t "$current_session" -p '#{pane_current_path}' 2>/dev/null || echo "")"
1462
1585
  repo_root="$(_tmux_shared_root_for_path "$session_dir" 2>/dev/null || true)"
1463
1586
  if [[ -z "$repo_root" ]]; then
1587
+ rm -f "$active_file"
1464
1588
  err "Unable to determine Orchestra workspace for session"
1465
1589
  return 1
1466
1590
  fi
1467
1591
  _tmux_registry_sync_active_workspace_sessions "$repo_root" >/dev/null 2>&1 || true
1468
1592
 
1469
- db_path="$(_tmux_session_registry_path)"
1470
1593
  if [[ ! -f "$db_path" ]]; then
1594
+ rm -f "$active_file"
1471
1595
  err "No Orchestra session registry found"
1472
1596
  return 1
1473
1597
  fi
1474
- have_cmd python3 || {
1475
- err "python3 is required to read the Orchestra session registry"
1476
- return 1
1477
- }
1478
1598
 
1479
- active_file="$(mktemp)"
1480
- tmux list-sessions -F '#{session_name}' > "$active_file" 2>/dev/null || {
1481
- rm -f "$active_file"
1482
- err "Unable to list tmux sessions"
1483
- return 1
1484
- }
1485
-
1486
- target="$(python3 - "$db_path" "$repo_root" "$current_session" "$direction" "$active_file" <<'PY'
1599
+ if target="$(python3 - "$db_path" "$repo_root" "$current_session" "$direction" "$active_file" <<'PY'
1487
1600
  import sqlite3
1488
1601
  import sys
1489
1602
 
1490
1603
  db_path, repo_root, current_session, direction, active_path = sys.argv[1:6]
1491
1604
  with open(active_path, "r", encoding="utf-8") as handle:
1492
- active = {line.strip() for line in handle if line.strip()}
1605
+ active = {
1606
+ line.rstrip("\n").split("\t", 1)[0].strip()
1607
+ for line in handle
1608
+ if line.rstrip("\n").split("\t", 1)[0].strip()
1609
+ }
1493
1610
 
1494
1611
  conn = sqlite3.connect(db_path)
1495
1612
  rows = conn.execute(
@@ -1519,8 +1636,11 @@ else:
1519
1636
  index = (index - 1) % len(names)
1520
1637
  print(names[index])
1521
1638
  PY
1522
- )"
1523
- local query_status=$?
1639
+ )"; then
1640
+ query_status=0
1641
+ else
1642
+ query_status=$?
1643
+ fi
1524
1644
  rm -f "$active_file"
1525
1645
  if [[ $query_status -ne 0 ]]; then
1526
1646
  err "Unable to query Orchestra session registry"
@@ -1543,13 +1663,15 @@ tmux_cycle_workspace_session() {
1543
1663
  return 1
1544
1664
  fi
1545
1665
 
1546
- _tmux_refresh_orchestra_session_status "$target_session" >/dev/null 2>&1 || true
1547
-
1548
1666
  if [[ -n "$target_client" ]]; then
1549
1667
  tmux switch-client -c "$target_client" -t "$target_session" >/dev/null 2>&1 || return 1
1550
1668
  else
1551
1669
  tmux switch-client -t "$target_session" >/dev/null 2>&1 || return 1
1552
1670
  fi
1671
+
1672
+ {
1673
+ _tmux_refresh_orchestra_session_status "$target_session" >/dev/null 2>&1 || true
1674
+ } &
1553
1675
  }
1554
1676
 
1555
1677
  # Load .env file if it exists