@humanu/orchestra 0.5.72 → 0.5.74
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
package/resources/api/tmux.sh
CHANGED
|
@@ -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,9 +498,9 @@ _tmux_status_escape_text() {
|
|
|
424
498
|
|
|
425
499
|
_tmux_truncate_tab_label() {
|
|
426
500
|
local label="$1"
|
|
427
|
-
local max_len="${2:-
|
|
501
|
+
local max_len="${2:-14}"
|
|
428
502
|
if (( ${#label} > max_len )); then
|
|
429
|
-
printf '%s
|
|
503
|
+
printf '%s' "${label:0:max_len}"
|
|
430
504
|
else
|
|
431
505
|
printf '%s' "$label"
|
|
432
506
|
fi
|
|
@@ -506,7 +580,9 @@ PY
|
|
|
506
580
|
_tmux_workspace_session_tabs() {
|
|
507
581
|
local current_session="$1"
|
|
508
582
|
local fallback_display_name="$2"
|
|
509
|
-
local session_dir repo_root rows tabs name display_name
|
|
583
|
+
local session_dir repo_root rows tabs name display_name tab_label escaped_tab_label divider active_style inactive_style muted_style reset_style
|
|
584
|
+
local tab_max_width=24
|
|
585
|
+
local active_label_max_width=22
|
|
510
586
|
|
|
511
587
|
session_dir="$(tmux display-message -t "$current_session" -p '#{pane_current_path}' 2>/dev/null || echo "")"
|
|
512
588
|
repo_root="$(_tmux_shared_root_for_path "$session_dir" 2>/dev/null || true)"
|
|
@@ -518,34 +594,42 @@ _tmux_workspace_session_tabs() {
|
|
|
518
594
|
fi
|
|
519
595
|
|
|
520
596
|
if [[ -z "$rows" ]]; then
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
printf '#[fg
|
|
597
|
+
tab_label="$(_tmux_truncate_tab_label "$fallback_display_name" "$active_label_max_width")"
|
|
598
|
+
escaped_tab_label="$(_tmux_status_escape_text "$tab_label")"
|
|
599
|
+
printf '#[bg=#414868] #[fg=#ff9e64,bg=#414868,bold]● #[fg=#c0caf5,bg=#414868,bold]%s #[default]' "$escaped_tab_label"
|
|
524
600
|
return
|
|
525
601
|
fi
|
|
526
602
|
|
|
603
|
+
# Tokyo Night palette: midnight footer, muted inactive tabs, orange active marker.
|
|
604
|
+
active_style="#[fg=#c0caf5,bg=#414868,bold]"
|
|
605
|
+
inactive_style="#[fg=#a9b1d6,bg=#24283b,nobold]"
|
|
606
|
+
muted_style="#[fg=#565f89,bg=#1a1b26,nobold]"
|
|
607
|
+
reset_style="#[default]"
|
|
527
608
|
tabs=""
|
|
528
|
-
divider="
|
|
609
|
+
divider="${muted_style}|${reset_style}"
|
|
529
610
|
while IFS=$'\t' read -r name display_name; do
|
|
530
611
|
[[ -n "$name" ]] || continue
|
|
531
612
|
if [[ -n "$tabs" ]]; then
|
|
532
613
|
tabs+="$divider"
|
|
533
614
|
fi
|
|
534
615
|
if [[ "$name" == "__ellipsis__" ]]; then
|
|
535
|
-
|
|
616
|
+
tab_label="⋯"
|
|
617
|
+
escaped_tab_label="$(_tmux_status_escape_text "$tab_label")"
|
|
618
|
+
tabs+="${muted_style} ${escaped_tab_label} ${reset_style}"
|
|
536
619
|
continue
|
|
537
620
|
fi
|
|
538
621
|
|
|
539
622
|
if [[ -z "$display_name" ]]; then
|
|
540
623
|
display_name="$(tmux_format_session_display "$name" without-timestamp)"
|
|
541
624
|
fi
|
|
542
|
-
label="$(_tmux_truncate_tab_label "$display_name")"
|
|
543
|
-
escaped_label="$(_tmux_status_escape_text "$label")"
|
|
544
|
-
|
|
545
625
|
if [[ "$name" == "$current_session" ]]; then
|
|
546
|
-
|
|
626
|
+
tab_label="$(_tmux_truncate_tab_label "$display_name" "$active_label_max_width")"
|
|
627
|
+
escaped_tab_label="$(_tmux_status_escape_text "$tab_label")"
|
|
628
|
+
tabs+="#[bg=#414868] #[fg=#ff9e64,bg=#414868,bold]● ${active_style}${escaped_tab_label} ${reset_style}"
|
|
547
629
|
else
|
|
548
|
-
|
|
630
|
+
tab_label="$(_tmux_truncate_tab_label "$display_name" "$tab_max_width")"
|
|
631
|
+
escaped_tab_label="$(_tmux_status_escape_text "$tab_label")"
|
|
632
|
+
tabs+="${inactive_style} ${escaped_tab_label} ${reset_style}"
|
|
549
633
|
fi
|
|
550
634
|
done <<< "$rows"
|
|
551
635
|
|
|
@@ -559,7 +643,7 @@ _tmux_orchestra_status_left() {
|
|
|
559
643
|
}
|
|
560
644
|
|
|
561
645
|
_tmux_orchestra_status_right() {
|
|
562
|
-
printf ''
|
|
646
|
+
printf '#[fg=#565f89,bg=#1a1b26]Ctrl+b,h for help#[default]'
|
|
563
647
|
}
|
|
564
648
|
|
|
565
649
|
_tmux_configure_orchestra_bindings() {
|
|
@@ -577,6 +661,8 @@ _tmux_configure_orchestra_bindings() {
|
|
|
577
661
|
|
|
578
662
|
tmux bind-key -T prefix '?' if-shell -F '#{@orchestra_display_name}' \
|
|
579
663
|
"run-shell -b \"$help_command\"" 'list-keys -N' >/dev/null 2>&1 || true
|
|
664
|
+
tmux bind-key -T prefix h if-shell -F '#{@orchestra_display_name}' \
|
|
665
|
+
"run-shell -b \"$help_command\"" 'refresh-client -S' >/dev/null 2>&1 || true
|
|
580
666
|
tmux bind-key -T prefix r if-shell -F '#{@orchestra_display_name}' \
|
|
581
667
|
"$prompt_command" 'refresh-client -S' >/dev/null 2>&1 || true
|
|
582
668
|
tmux bind-key -T prefix '>' if-shell -F '#{@orchestra_display_name}' \
|
|
@@ -604,10 +690,11 @@ _tmux_configure_orchestra_status() {
|
|
|
604
690
|
tmux set-option -t "$session_name" @orchestra_worktree_name "$worktree_name" >/dev/null 2>&1 || true
|
|
605
691
|
tmux set-option -t "$session_name" status on >/dev/null 2>&1 || true
|
|
606
692
|
tmux set-option -t "$session_name" status-position bottom >/dev/null 2>&1 || true
|
|
693
|
+
tmux set-option -t "$session_name" status-style "fg=#c0caf5,bg=#1a1b26" >/dev/null 2>&1 || true
|
|
607
694
|
tmux set-option -t "$session_name" status-left "$status_left" >/dev/null 2>&1 || true
|
|
608
695
|
tmux set-option -t "$session_name" status-left-length 1000 >/dev/null 2>&1 || true
|
|
609
696
|
tmux set-option -t "$session_name" status-right "$status_right" >/dev/null 2>&1 || true
|
|
610
|
-
tmux set-option -t "$session_name" status-right-length
|
|
697
|
+
tmux set-option -t "$session_name" status-right-length 40 >/dev/null 2>&1 || true
|
|
611
698
|
tmux set-option -t "$session_name" window-status-format "" >/dev/null 2>&1 || true
|
|
612
699
|
tmux set-option -t "$session_name" window-status-current-format "" >/dev/null 2>&1 || true
|
|
613
700
|
tmux set-option -t "$session_name" window-status-separator "" >/dev/null 2>&1 || true
|
|
@@ -1416,21 +1503,32 @@ tmux_show_orchestra_help_popup() {
|
|
|
1416
1503
|
fi
|
|
1417
1504
|
|
|
1418
1505
|
local popup_command
|
|
1419
|
-
popup_command=
|
|
1506
|
+
popup_command="$(cat <<'EOF'
|
|
1507
|
+
bash -lc '
|
|
1508
|
+
trap "exit 0" INT TERM
|
|
1509
|
+
printf "%s\n" \
|
|
1420
1510
|
"Orchestra tmux shortcuts" \
|
|
1421
1511
|
"" \
|
|
1512
|
+
"Ctrl+b, d Detach and return to Orchestra" \
|
|
1513
|
+
"Ctrl+b, r Rename the current Orchestra session" \
|
|
1514
|
+
"" \
|
|
1422
1515
|
"Ctrl+b, Left Previous Orchestra session in this workspace" \
|
|
1423
1516
|
"Ctrl+b, Right Next Orchestra session in this workspace" \
|
|
1424
1517
|
"Ctrl+b, < Previous Orchestra session in this workspace" \
|
|
1425
1518
|
"Ctrl+b, > Next Orchestra session in this workspace" \
|
|
1426
|
-
"
|
|
1427
|
-
"Ctrl+b, d Detach and return to Orchestra" \
|
|
1519
|
+
"" \
|
|
1428
1520
|
"Ctrl+b, [ Copy/scroll mode" \
|
|
1521
|
+
"Ctrl+b, h Show this help" \
|
|
1429
1522
|
"Ctrl+b, ? Show this help" \
|
|
1430
1523
|
"" \
|
|
1431
|
-
"Press
|
|
1524
|
+
"Press any key to close..."
|
|
1525
|
+
IFS= read -rsn1 _ || true
|
|
1526
|
+
exit 0
|
|
1527
|
+
'
|
|
1528
|
+
EOF
|
|
1529
|
+
)"
|
|
1432
1530
|
|
|
1433
|
-
tmux display-popup "${target_args[@]}" -E -w 78 -h
|
|
1531
|
+
tmux display-popup "${target_args[@]}" -E -w 78 -h 18 -T "Orchestra shortcuts" "$popup_command" >/dev/null 2>&1 || true
|
|
1434
1532
|
}
|
|
1435
1533
|
|
|
1436
1534
|
# Find the adjacent active Orchestra session registered for the current repo.
|
|
@@ -1438,7 +1536,7 @@ tmux_show_orchestra_help_popup() {
|
|
|
1438
1536
|
tmux_workspace_cycle_target() {
|
|
1439
1537
|
local current_session="$1"
|
|
1440
1538
|
local direction="$2"
|
|
1441
|
-
local session_dir repo_root db_path active_file target
|
|
1539
|
+
local session_dir repo_root db_path active_file target query_status
|
|
1442
1540
|
|
|
1443
1541
|
if ! tmux_available; then
|
|
1444
1542
|
err "tmux not installed"
|
|
@@ -1456,40 +1554,64 @@ tmux_workspace_cycle_target() {
|
|
|
1456
1554
|
;;
|
|
1457
1555
|
esac
|
|
1458
1556
|
|
|
1557
|
+
db_path="$(_tmux_session_registry_path)"
|
|
1558
|
+
have_cmd python3 || {
|
|
1559
|
+
err "python3 is required to read the Orchestra session registry"
|
|
1560
|
+
return 1
|
|
1561
|
+
}
|
|
1562
|
+
|
|
1563
|
+
active_file="$(mktemp)"
|
|
1564
|
+
tmux list-sessions -F $'#{session_name}\t#{@orchestra_display_name}' > "$active_file" 2>/dev/null || {
|
|
1565
|
+
rm -f "$active_file"
|
|
1566
|
+
err "Unable to list tmux sessions"
|
|
1567
|
+
return 1
|
|
1568
|
+
}
|
|
1569
|
+
|
|
1570
|
+
if [[ -f "$db_path" ]]; then
|
|
1571
|
+
if target="$(_tmux_workspace_cycle_target_cached "$current_session" "$direction" "$db_path" "$active_file")"; then
|
|
1572
|
+
query_status=0
|
|
1573
|
+
else
|
|
1574
|
+
query_status=$?
|
|
1575
|
+
fi
|
|
1576
|
+
if [[ $query_status -eq 0 && -n "$target" ]]; then
|
|
1577
|
+
rm -f "$active_file"
|
|
1578
|
+
printf '%s\n' "$target"
|
|
1579
|
+
return 0
|
|
1580
|
+
fi
|
|
1581
|
+
if [[ $query_status -eq 3 ]]; then
|
|
1582
|
+
rm -f "$active_file"
|
|
1583
|
+
return 1
|
|
1584
|
+
fi
|
|
1585
|
+
fi
|
|
1586
|
+
|
|
1459
1587
|
_tmux_registry_upsert_current_session "$current_session" >/dev/null 2>&1 || true
|
|
1460
1588
|
|
|
1461
1589
|
session_dir="$(tmux display-message -t "$current_session" -p '#{pane_current_path}' 2>/dev/null || echo "")"
|
|
1462
1590
|
repo_root="$(_tmux_shared_root_for_path "$session_dir" 2>/dev/null || true)"
|
|
1463
1591
|
if [[ -z "$repo_root" ]]; then
|
|
1592
|
+
rm -f "$active_file"
|
|
1464
1593
|
err "Unable to determine Orchestra workspace for session"
|
|
1465
1594
|
return 1
|
|
1466
1595
|
fi
|
|
1467
1596
|
_tmux_registry_sync_active_workspace_sessions "$repo_root" >/dev/null 2>&1 || true
|
|
1468
1597
|
|
|
1469
|
-
db_path="$(_tmux_session_registry_path)"
|
|
1470
1598
|
if [[ ! -f "$db_path" ]]; then
|
|
1599
|
+
rm -f "$active_file"
|
|
1471
1600
|
err "No Orchestra session registry found"
|
|
1472
1601
|
return 1
|
|
1473
1602
|
fi
|
|
1474
|
-
have_cmd python3 || {
|
|
1475
|
-
err "python3 is required to read the Orchestra session registry"
|
|
1476
|
-
return 1
|
|
1477
|
-
}
|
|
1478
|
-
|
|
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
1603
|
|
|
1486
|
-
target="$(python3 - "$db_path" "$repo_root" "$current_session" "$direction" "$active_file" <<'PY'
|
|
1604
|
+
if target="$(python3 - "$db_path" "$repo_root" "$current_session" "$direction" "$active_file" <<'PY'
|
|
1487
1605
|
import sqlite3
|
|
1488
1606
|
import sys
|
|
1489
1607
|
|
|
1490
1608
|
db_path, repo_root, current_session, direction, active_path = sys.argv[1:6]
|
|
1491
1609
|
with open(active_path, "r", encoding="utf-8") as handle:
|
|
1492
|
-
active = {
|
|
1610
|
+
active = {
|
|
1611
|
+
line.rstrip("\n").split("\t", 1)[0].strip()
|
|
1612
|
+
for line in handle
|
|
1613
|
+
if line.rstrip("\n").split("\t", 1)[0].strip()
|
|
1614
|
+
}
|
|
1493
1615
|
|
|
1494
1616
|
conn = sqlite3.connect(db_path)
|
|
1495
1617
|
rows = conn.execute(
|
|
@@ -1519,8 +1641,11 @@ else:
|
|
|
1519
1641
|
index = (index - 1) % len(names)
|
|
1520
1642
|
print(names[index])
|
|
1521
1643
|
PY
|
|
1522
|
-
)"
|
|
1523
|
-
|
|
1644
|
+
)"; then
|
|
1645
|
+
query_status=0
|
|
1646
|
+
else
|
|
1647
|
+
query_status=$?
|
|
1648
|
+
fi
|
|
1524
1649
|
rm -f "$active_file"
|
|
1525
1650
|
if [[ $query_status -ne 0 ]]; then
|
|
1526
1651
|
err "Unable to query Orchestra session registry"
|
|
@@ -1543,13 +1668,15 @@ tmux_cycle_workspace_session() {
|
|
|
1543
1668
|
return 1
|
|
1544
1669
|
fi
|
|
1545
1670
|
|
|
1546
|
-
_tmux_refresh_orchestra_session_status "$target_session" >/dev/null 2>&1 || true
|
|
1547
|
-
|
|
1548
1671
|
if [[ -n "$target_client" ]]; then
|
|
1549
1672
|
tmux switch-client -c "$target_client" -t "$target_session" >/dev/null 2>&1 || return 1
|
|
1550
1673
|
else
|
|
1551
1674
|
tmux switch-client -t "$target_session" >/dev/null 2>&1 || return 1
|
|
1552
1675
|
fi
|
|
1676
|
+
|
|
1677
|
+
{
|
|
1678
|
+
_tmux_refresh_orchestra_session_status "$target_session" >/dev/null 2>&1 || true
|
|
1679
|
+
} &
|
|
1553
1680
|
}
|
|
1554
1681
|
|
|
1555
1682
|
# Load .env file if it exists
|
|
Binary file
|
|
Binary file
|
|
Binary file
|