zui-agent-manager 0.1.1 → 0.1.2

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.
Files changed (3) hide show
  1. package/README.md +1 -13
  2. package/dist/index.js +169 -3
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -2,19 +2,7 @@
2
2
 
3
3
  A terminal UI for managing [Claude Code](https://docs.anthropic.com/en/docs/claude-code) agents running in tmux sessions.
4
4
 
5
- ```
6
- ┌─────────────────────── zui - Agent Manager ───────────────────────┐
7
- │ │
8
- │ Session Status Running Preview │
9
- │ ────────────────────────────────────────────────────────────── │
10
- │> myapp-feat-auth [WORK] 12m 34s Implementing login... │
11
- │ myapp-fix-api [WAIT] 3m 12s Allow tool use? (y/n) │
12
- │ myapp-main [IDLE] 1h 5m > │
13
- │ │
14
- │ Ent:View g:Git Tab:Pane n:New y:YOLO w:Tree s:Set h:Help k:Kill │
15
- └────────────────────────────────────────────────────────────────────┘
16
- ```
17
-
5
+ <img width="1728" height="1087" alt="image" src="https://github.com/user-attachments/assets/edfcb7fe-b18f-49a4-a385-e2d76bfb1a8f" />
18
6
 
19
7
  ## Features
20
8
 
package/dist/index.js CHANGED
@@ -518,10 +518,64 @@ function showLazygitPane(workdir, rightWidth = 70, lazygitHeight = 40) {
518
518
  function killBottomRightPane() {
519
519
  runCommand("tmux", ["kill-pane", "-t", "{bottom-right}"]);
520
520
  }
521
+ function closeRightPane() {
522
+ if (getPaneCount() <= 1) return false;
523
+ const baseIdx = runCommand("tmux", ["show-options", "-gv", "pane-base-index"]);
524
+ const first = /^\d+$/.test(baseIdx) ? baseIdx : "0";
525
+ return runCommandOk("tmux", ["kill-pane", "-a", "-t", `zui-manager:zui.${first}`]);
526
+ }
527
+ function focusBottomRightPane() {
528
+ runCommand("tmux", ["select-pane", "-t", "{bottom-right}"]);
529
+ }
521
530
  function killZuiSession() {
522
531
  runCommand("tmux", ["kill-session", "-t", "zui-manager"]);
523
532
  }
524
533
 
534
+ // src/ui/keybindings.ts
535
+ var ALT_KEYS = [
536
+ "M-0",
537
+ "M-1",
538
+ "M-2",
539
+ "M-3",
540
+ "M-4",
541
+ "M-5",
542
+ "M-6",
543
+ "M-7",
544
+ "M-8",
545
+ "M-9",
546
+ "M-Enter",
547
+ "M-Tab",
548
+ "M-n",
549
+ "M-y",
550
+ "M-k",
551
+ "M-x",
552
+ "M-g",
553
+ "M-w",
554
+ "M-s",
555
+ "M-h",
556
+ "M-q",
557
+ "M-c"
558
+ ];
559
+ function getFirstPaneIndex() {
560
+ const result = runCommand("tmux", ["show-options", "-gv", "pane-base-index"]);
561
+ return /^\d+$/.test(result) ? result : "0";
562
+ }
563
+ function registerAltBindings() {
564
+ const first = getFirstPaneIndex();
565
+ const condition = `[ "#{session_name}" = "zui-manager" ] && [ "#{pane_index}" != "${first}" ]`;
566
+ for (const key of ALT_KEYS) {
567
+ const target = `zui-manager:zui.${first}`;
568
+ const action = key === "M-Tab" ? `select-pane -t ${target}` : `send-keys -t ${target} ${key}`;
569
+ const fallback = `send-keys ${key}`;
570
+ runCommandOk("tmux", ["bind-key", "-n", key, "if-shell", condition, action, fallback]);
571
+ }
572
+ }
573
+ function unregisterAltBindings() {
574
+ for (const key of ALT_KEYS) {
575
+ runCommandOk("tmux", ["unbind-key", "-n", key]);
576
+ }
577
+ }
578
+
525
579
  // src/ui/Header.tsx
526
580
  import { Box, Text } from "ink";
527
581
  import { jsx } from "react/jsx-runtime";
@@ -533,7 +587,7 @@ function Header() {
533
587
  import { Box as Box2, Text as Text2 } from "ink";
534
588
  import { jsx as jsx2 } from "react/jsx-runtime";
535
589
  function Footer() {
536
- return /* @__PURE__ */ jsx2(Box2, { justifyContent: "center", width: "100%", children: /* @__PURE__ */ jsx2(Text2, { backgroundColor: "cyan", color: "black", children: " 1-9:Jump Ent:View g:Git Tab:Pane n:New y:YOLO w:Tree s:Set h:Help k:Kill q:Quit " }) });
590
+ return /* @__PURE__ */ jsx2(Box2, { justifyContent: "center", width: "100%", children: /* @__PURE__ */ jsx2(Text2, { backgroundColor: "cyan", color: "black", children: " 1-9:Jump Ent:View g:Git Tab:Pane n:New y:YOLO w:Tree s:Set h:Help k:Kill q:Quit Alt:Remote " }) });
537
591
  }
538
592
 
539
593
  // src/ui/SessionList.tsx
@@ -781,6 +835,18 @@ var sections = [
781
835
  ["r", "Refresh session list"],
782
836
  ["h", "This help screen"],
783
837
  ["q/Esc", "Quit ZUI"]
838
+ ] },
839
+ { title: "Remote Control (from session pane)", items: [
840
+ ["Alt+1-9", "Jump to session by index"],
841
+ ["Alt+0", "Jump to session 10"],
842
+ ["Alt+Enter", "View selected session"],
843
+ ["Alt+Tab", "Toggle focus (ZUI \u2194 pane)"],
844
+ ["Alt+n/y", "New / YOLO session"],
845
+ ["Alt+k", "Kill selected session"],
846
+ ["Alt+g", "Show + focus lazygit"],
847
+ ["Alt+w", "Create worktree"],
848
+ ["Alt+c", "Close right pane"],
849
+ ["Alt+q", "Quit ZUI"]
784
850
  ] }
785
851
  ];
786
852
  function HelpDialog({ onClose }) {
@@ -865,6 +931,65 @@ function App({ config: initialConfig, initialFocus }) {
865
931
  }
866
932
  }, [sessions, selected]);
867
933
  useInput6((input, key) => {
934
+ if (key.meta && key.return && sessions.length > 0) {
935
+ viewSession();
936
+ return;
937
+ }
938
+ if (key.meta && input.length > 0) {
939
+ if (/^[0-9]$/.test(input) && sessions.length > 0) {
940
+ const idx = input === "0" ? 9 : parseInt(input, 10) - 1;
941
+ if (idx < sessions.length) {
942
+ setSelected(idx);
943
+ const session = sessions[idx];
944
+ if (showSessionInPane(session.name, config)) {
945
+ focusRightPane();
946
+ setStatus(`Showing: ${session.name}`);
947
+ }
948
+ }
949
+ return;
950
+ }
951
+ if (input === "q") {
952
+ shutdownZui();
953
+ return;
954
+ }
955
+ if (input === "n") {
956
+ launchSession(false);
957
+ return;
958
+ }
959
+ if (input === "y") {
960
+ launchSession(true);
961
+ return;
962
+ }
963
+ if (input === "k" && sessions.length > 0) {
964
+ killSessionAction();
965
+ return;
966
+ }
967
+ if (input === "x") {
968
+ cleanupWorktree();
969
+ return;
970
+ }
971
+ if (input === "g" && sessions.length > 0) {
972
+ showLazygitFromRemote();
973
+ return;
974
+ }
975
+ if (input === "w") {
976
+ createWorktreeAction();
977
+ return;
978
+ }
979
+ if (input === "s") {
980
+ setDialog({ type: "settings" });
981
+ return;
982
+ }
983
+ if (input === "h") {
984
+ setDialog({ type: "help" });
985
+ return;
986
+ }
987
+ if (input === "c") {
988
+ if (closeRightPane()) setStatus("Pane closed");
989
+ return;
990
+ }
991
+ return;
992
+ }
868
993
  if (dialog.type !== "none") return;
869
994
  if (sessions.length > 0 && /^[1-9]$/.test(input)) {
870
995
  const idx = parseInt(input, 10) - 1;
@@ -879,8 +1004,7 @@ function App({ config: initialConfig, initialFocus }) {
879
1004
  return;
880
1005
  }
881
1006
  if (input === "q" || key.escape) {
882
- killZuiSession();
883
- exit();
1007
+ shutdownZui();
884
1008
  return;
885
1009
  }
886
1010
  if (input === "r") {
@@ -906,6 +1030,11 @@ function App({ config: initialConfig, initialFocus }) {
906
1030
  if (input === "h") setDialog({ type: "help" });
907
1031
  if (key.tab) focusRightPane();
908
1032
  });
1033
+ function shutdownZui() {
1034
+ unregisterAltBindings();
1035
+ killZuiSession();
1036
+ exit();
1037
+ }
909
1038
  function viewSession() {
910
1039
  const session = sessions[selected];
911
1040
  if (!session) return;
@@ -916,6 +1045,33 @@ function App({ config: initialConfig, initialFocus }) {
916
1045
  setStatus("Error: Failed to open pane");
917
1046
  }
918
1047
  }
1048
+ function showLazygitFromRemote() {
1049
+ const numPanes = getPaneCount();
1050
+ const session = sessions[selected];
1051
+ if (!session) return;
1052
+ if (numPanes >= 3) {
1053
+ focusBottomRightPane();
1054
+ return;
1055
+ }
1056
+ const workdir = getSessionWorkdir(session.name, config);
1057
+ if (!workdir) {
1058
+ setStatus("Error: Can't find session workdir");
1059
+ return;
1060
+ }
1061
+ if (numPanes < 2) {
1062
+ if (showSessionInPane(session.name, config)) {
1063
+ setTimeout(() => {
1064
+ showLazygitPane(workdir, config.layoutRightWidth, config.layoutLazygitHeight);
1065
+ focusBottomRightPane();
1066
+ setStatus(`View + Git: ${session.name}`);
1067
+ }, 200);
1068
+ }
1069
+ } else {
1070
+ showLazygitPane(workdir, config.layoutRightWidth, config.layoutLazygitHeight);
1071
+ focusBottomRightPane();
1072
+ setStatus(`Git: ${workdir.split("/").pop()}`);
1073
+ }
1074
+ }
919
1075
  function launchSession(yolo) {
920
1076
  const refreshedProjects = discoverProjects(config);
921
1077
  setProjects(refreshedProjects);
@@ -1223,6 +1379,16 @@ function main() {
1223
1379
  }
1224
1380
  const initialFocus = focusArg ? parseInt(focusArg, 10) : void 0;
1225
1381
  const config = loadConfig();
1382
+ registerAltBindings();
1383
+ process2.on("exit", () => unregisterAltBindings());
1384
+ process2.on("SIGINT", () => {
1385
+ unregisterAltBindings();
1386
+ process2.exit();
1387
+ });
1388
+ process2.on("SIGTERM", () => {
1389
+ unregisterAltBindings();
1390
+ process2.exit();
1391
+ });
1226
1392
  render(React5.createElement(App, { config, initialFocus }));
1227
1393
  }
1228
1394
  main();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zui-agent-manager",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "TUI for managing AI coding agents (Claude Code) in tmux sessions",
5
5
  "type": "module",
6
6
  "bin": {