dmux 3.0.2 → 3.1.1

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 (102) hide show
  1. package/dist/DmuxApp.d.ts.map +1 -1
  2. package/dist/DmuxApp.js +242 -23
  3. package/dist/DmuxApp.js.map +1 -1
  4. package/dist/PaneAnalyzer.d.ts +0 -4
  5. package/dist/PaneAnalyzer.d.ts.map +1 -1
  6. package/dist/PaneAnalyzer.js +2 -17
  7. package/dist/PaneAnalyzer.js.map +1 -1
  8. package/dist/_plugin-vue_export-helper.css +1 -1
  9. package/dist/actions/paneActions.d.ts.map +1 -1
  10. package/dist/actions/paneActions.js +94 -40
  11. package/dist/actions/paneActions.js.map +1 -1
  12. package/dist/components/ActionConfirmDialog.js +1 -1
  13. package/dist/components/ActionConfirmDialog.js.map +1 -1
  14. package/dist/components/CloseOptionsDialog.d.ts.map +1 -1
  15. package/dist/components/CloseOptionsDialog.js +9 -7
  16. package/dist/components/CloseOptionsDialog.js.map +1 -1
  17. package/dist/components/FooterHelp.js +1 -1
  18. package/dist/components/FooterHelp.js.map +1 -1
  19. package/dist/components/HooksDialog.d.ts +12 -0
  20. package/dist/components/HooksDialog.d.ts.map +1 -0
  21. package/dist/components/HooksDialog.js +52 -0
  22. package/dist/components/HooksDialog.js.map +1 -0
  23. package/dist/components/MergeConfirmationDialog.d.ts.map +1 -1
  24. package/dist/components/MergeConfirmationDialog.js +2 -1
  25. package/dist/components/MergeConfirmationDialog.js.map +1 -1
  26. package/dist/components/NewPaneDialog.d.ts.map +1 -1
  27. package/dist/components/NewPaneDialog.js +1 -3
  28. package/dist/components/NewPaneDialog.js.map +1 -1
  29. package/dist/components/SettingsDialog.d.ts +16 -0
  30. package/dist/components/SettingsDialog.d.ts.map +1 -0
  31. package/dist/components/SettingsDialog.js +95 -0
  32. package/dist/components/SettingsDialog.js.map +1 -0
  33. package/dist/dashboard.js +2 -2
  34. package/dist/hooks/useAutoUpdater.js +2 -2
  35. package/dist/hooks/useAutoUpdater.js.map +1 -1
  36. package/dist/hooks/usePaneCreation.d.ts.map +1 -1
  37. package/dist/hooks/usePaneCreation.js +22 -3
  38. package/dist/hooks/usePaneCreation.js.map +1 -1
  39. package/dist/hooks/usePanes.js +2 -2
  40. package/dist/hooks/usePanes.js.map +1 -1
  41. package/dist/hooks/useTerminalWidth.d.ts.map +1 -1
  42. package/dist/hooks/useTerminalWidth.js +5 -0
  43. package/dist/hooks/useTerminalWidth.js.map +1 -1
  44. package/dist/hooks/useWorktreeActions.js +4 -4
  45. package/dist/hooks/useWorktreeActions.js.map +1 -1
  46. package/dist/server/embedded-assets.d.ts.map +1 -1
  47. package/dist/server/embedded-assets.js +251 -47
  48. package/dist/server/embedded-assets.js.map +1 -1
  49. package/dist/server/index.d.ts.map +1 -1
  50. package/dist/server/index.js +2 -1
  51. package/dist/server/index.js.map +1 -1
  52. package/dist/server/routes.d.ts.map +1 -1
  53. package/dist/server/routes.js +195 -55
  54. package/dist/server/routes.js.map +1 -1
  55. package/dist/services/ConfigWatcher.d.ts +9 -0
  56. package/dist/services/ConfigWatcher.d.ts.map +1 -1
  57. package/dist/services/ConfigWatcher.js +17 -0
  58. package/dist/services/ConfigWatcher.js.map +1 -1
  59. package/dist/services/StatusDetector.js +7 -7
  60. package/dist/services/StatusDetector.js.map +1 -1
  61. package/dist/services/TunnelService.d.ts.map +1 -1
  62. package/dist/services/TunnelService.js +25 -3
  63. package/dist/services/TunnelService.js.map +1 -1
  64. package/dist/shared/StateManager.d.ts +11 -0
  65. package/dist/shared/StateManager.d.ts.map +1 -1
  66. package/dist/shared/StateManager.js +26 -0
  67. package/dist/shared/StateManager.js.map +1 -1
  68. package/dist/types.d.ts +16 -0
  69. package/dist/types.d.ts.map +1 -1
  70. package/dist/utils/conflictResolutionPane.d.ts.map +1 -1
  71. package/dist/utils/conflictResolutionPane.js +3 -2
  72. package/dist/utils/conflictResolutionPane.js.map +1 -1
  73. package/dist/utils/generated-agents-doc.d.ts +6 -0
  74. package/dist/utils/generated-agents-doc.d.ts.map +1 -0
  75. package/dist/utils/generated-agents-doc.js +430 -0
  76. package/dist/utils/generated-agents-doc.js.map +1 -0
  77. package/dist/utils/hooks.d.ts +70 -0
  78. package/dist/utils/hooks.d.ts.map +1 -0
  79. package/dist/utils/hooks.js +216 -0
  80. package/dist/utils/hooks.js.map +1 -0
  81. package/dist/utils/hooksDocs.d.ts +42 -0
  82. package/dist/utils/hooksDocs.d.ts.map +1 -0
  83. package/dist/utils/hooksDocs.js +325 -0
  84. package/dist/utils/hooksDocs.js.map +1 -0
  85. package/dist/utils/paneCapture.d.ts +21 -0
  86. package/dist/utils/paneCapture.d.ts.map +1 -0
  87. package/dist/utils/paneCapture.js +96 -0
  88. package/dist/utils/paneCapture.js.map +1 -0
  89. package/dist/utils/paneCreation.d.ts +1 -0
  90. package/dist/utils/paneCreation.d.ts.map +1 -1
  91. package/dist/utils/paneCreation.js +90 -18
  92. package/dist/utils/paneCreation.js.map +1 -1
  93. package/dist/utils/settingsManager.d.ts +49 -0
  94. package/dist/utils/settingsManager.d.ts.map +1 -0
  95. package/dist/utils/settingsManager.js +172 -0
  96. package/dist/utils/settingsManager.js.map +1 -0
  97. package/dist/utils/tmux.d.ts.map +1 -1
  98. package/dist/utils/tmux.js +79 -20
  99. package/dist/utils/tmux.js.map +1 -1
  100. package/dist/workers/PaneWorker.js +3 -6
  101. package/dist/workers/PaneWorker.js.map +1 -1
  102. package/package.json +4 -3
@@ -1 +1 @@
1
- {"version":3,"file":"DmuxApp.d.ts","sourceRoot":"","sources":["../src/DmuxApp.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA8B,MAAM,OAAO,CAAC;AA8BnD,OAAO,KAAK,EAA2C,YAAY,EAAE,MAAM,YAAY,CAAC;AAmBxF,QAAA,MAAM,OAAO,EAAE,KAAK,CAAC,EAAE,CAAC,YAAY,CAkyCnC,CAAC;AAEF,eAAe,OAAO,CAAC"}
1
+ {"version":3,"file":"DmuxApp.d.ts","sourceRoot":"","sources":["../src/DmuxApp.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA8B,MAAM,OAAO,CAAC;AAgCnD,OAAO,KAAK,EAA2C,YAAY,EAAE,MAAM,YAAY,CAAC;AAqBxF,QAAA,MAAM,OAAO,EAAE,KAAK,CAAC,EAAE,CAAC,YAAY,CA4gDnC,CAAC;AAEF,eAAe,OAAO,CAAC"}
package/dist/DmuxApp.js CHANGED
@@ -19,9 +19,11 @@ import { applySmartLayout } from './utils/tmux.js';
19
19
  import { suggestCommand } from './utils/commands.js';
20
20
  import { generateSlug } from './utils/slug.js';
21
21
  import { getMainBranch } from './utils/git.js';
22
+ import { capturePaneContent } from './utils/paneCapture.js';
22
23
  import { StateManager } from './shared/StateManager.js';
23
24
  import { getStatusDetector } from './services/StatusDetector.js';
24
25
  import { PaneAction, getAvailableActions } from './actions/index.js';
26
+ import { SettingsManager, SETTING_DEFINITIONS } from './utils/settingsManager.js';
25
27
  const require = createRequire(import.meta.url);
26
28
  const packageJson = require('../package.json');
27
29
  import PanesGrid from './components/PanesGrid.js';
@@ -40,7 +42,9 @@ import ActionChoiceDialog from './components/ActionChoiceDialog.js';
40
42
  import ActionConfirmDialog from './components/ActionConfirmDialog.js';
41
43
  import ActionInputDialog from './components/ActionInputDialog.js';
42
44
  import ActionProgressDialog from './components/ActionProgressDialog.js';
43
- const DmuxApp = ({ panesFile, projectName, sessionName, settingsFile, autoUpdater, serverPort, server }) => {
45
+ import SettingsDialog from './components/SettingsDialog.js';
46
+ import HooksDialog from './components/HooksDialog.js';
47
+ const DmuxApp = ({ panesFile, projectName, sessionName, settingsFile, projectRoot, autoUpdater, serverPort, server }) => {
44
48
  /* panes state moved to usePanes */
45
49
  const [selectedIndex, setSelectedIndex] = useState(0);
46
50
  const [showNewPaneDialog, setShowNewPaneDialog] = useState(false);
@@ -50,9 +54,23 @@ const DmuxApp = ({ panesFile, projectName, sessionName, settingsFile, autoUpdate
50
54
  const [showQRCode, setShowQRCode] = useState(false);
51
55
  const [tunnelUrl, setTunnelUrl] = useState(null);
52
56
  const [isCreatingTunnel, setIsCreatingTunnel] = useState(false);
57
+ // Settings state
58
+ const [settingsManager] = useState(() => new SettingsManager(projectRoot));
59
+ const [showSettingsDialog, setShowSettingsDialog] = useState(false);
60
+ const [settingsMode, setSettingsMode] = useState('list');
61
+ const [settingsSelectedIndex, setSettingsSelectedIndex] = useState(0);
62
+ const [settingsEditingKey, setSettingsEditingKey] = useState();
63
+ const [settingsEditingValueIndex, setSettingsEditingValueIndex] = useState(0);
64
+ const [settingsScopeIndex, setSettingsScopeIndex] = useState(0);
53
65
  // Force repaint trigger - incrementing this causes Ink to re-render
54
66
  const [forceRepaintTrigger, setForceRepaintTrigger] = useState(0);
67
+ // Spinner state - shows for a few frames to force render
68
+ const [showRepaintSpinner, setShowRepaintSpinner] = useState(false);
55
69
  const { projectSettings, saveSettings } = useProjectSettings(settingsFile);
70
+ // Hooks management state
71
+ const [showHooksDialog, setShowHooksDialog] = useState(false);
72
+ const [hooksSelectedIndex, setHooksSelectedIndex] = useState(0);
73
+ const [hooksData, setHooksData] = useState([]);
56
74
  const [showCommandPrompt, setShowCommandPrompt] = useState(null);
57
75
  const [commandInput, setCommandInput] = useState('');
58
76
  const [showFileCopyPrompt, setShowFileCopyPrompt] = useState(false);
@@ -63,6 +81,8 @@ const DmuxApp = ({ panesFile, projectName, sessionName, settingsFile, autoUpdate
63
81
  const [kebabMenuPaneIndex, setKebabMenuPaneIndex] = useState(null);
64
82
  const [kebabMenuOption, setKebabMenuOption] = useState(0);
65
83
  const [kebabMenuActions, setKebabMenuActions] = useState([]);
84
+ // Debug message state - for temporary logging messages
85
+ const [debugMessage, setDebugMessage] = useState('');
66
86
  // Update state handled by hook
67
87
  const { updateInfo, showUpdateDialog, isUpdating, performUpdate, skipUpdate, dismissUpdate, updateAvailable } = useAutoUpdater(autoUpdater, setStatusMessage);
68
88
  const { exit } = useApp();
@@ -104,8 +124,13 @@ const DmuxApp = ({ panesFile, projectName, sessionName, settingsFile, autoUpdate
104
124
  setStatusMessage,
105
125
  setRunningCommand,
106
126
  });
107
- // Force repaint helper
108
- const forceRepaint = () => setForceRepaintTrigger(prev => prev + 1);
127
+ // Force repaint helper - shows spinner for a few frames to force full re-render
128
+ const forceRepaint = () => {
129
+ setForceRepaintTrigger(prev => prev + 1);
130
+ setShowRepaintSpinner(true);
131
+ // Hide spinner after a few frames (enough to trigger multiple renders)
132
+ setTimeout(() => setShowRepaintSpinner(false), 100);
133
+ };
109
134
  // Force repaint effect - ensures Ink re-renders when trigger changes
110
135
  useEffect(() => {
111
136
  if (forceRepaintTrigger > 0) {
@@ -120,7 +145,7 @@ const DmuxApp = ({ panesFile, projectName, sessionName, settingsFile, autoUpdate
120
145
  }
121
146
  }, [forceRepaintTrigger]);
122
147
  // Pane creation
123
- const { openInEditor: openEditor2, createNewPane: createNewPaneHook } = usePaneCreation({
148
+ const { createNewPane: createNewPaneHook } = usePaneCreation({
124
149
  panes,
125
150
  savePanes,
126
151
  projectName,
@@ -204,6 +229,14 @@ const DmuxApp = ({ panesFile, projectName, sessionName, settingsFile, autoUpdate
204
229
  const stateManager = StateManager.getInstance();
205
230
  stateManager.updateSettings(projectSettings);
206
231
  }, [projectSettings]);
232
+ // Expose debug message setter via StateManager
233
+ useEffect(() => {
234
+ const stateManager = StateManager.getInstance();
235
+ stateManager.setDebugMessageCallback(setDebugMessage);
236
+ return () => {
237
+ stateManager.setDebugMessageCallback(undefined);
238
+ };
239
+ }, []);
207
240
  // Load panes and settings on mount and refresh periodically
208
241
  useEffect(() => {
209
242
  // SIGTERM should quit immediately (for process management)
@@ -211,6 +244,11 @@ const DmuxApp = ({ panesFile, projectName, sessionName, settingsFile, autoUpdate
211
244
  cleanExit();
212
245
  };
213
246
  process.on('SIGTERM', handleTermination);
247
+ // Test debug message on mount
248
+ StateManager.getInstance().setDebugMessage('Debug logging initialized - watching for AI activity...');
249
+ setTimeout(() => {
250
+ StateManager.getInstance().setDebugMessage('');
251
+ }, 3000);
214
252
  return () => {
215
253
  process.removeListener('SIGTERM', handleTermination);
216
254
  };
@@ -432,8 +470,7 @@ const DmuxApp = ({ panesFile, projectName, sessionName, settingsFile, autoUpdate
432
470
  await new Promise(resolve => setTimeout(resolve, checkInterval));
433
471
  try {
434
472
  // Capture the pane content
435
- const paneContent = execSync(`tmux capture-pane -t '${paneInfo}' -p -S -30`, // Capture last 30 lines
436
- { encoding: 'utf-8', stdio: 'pipe' });
473
+ const paneContent = capturePaneContent(paneInfo, 30);
437
474
  if (i % 10 === 0) { // Log every 10 checks (every second)
438
475
  }
439
476
  // Check if content has stabilized (same for 3 checks = prompt is waiting)
@@ -477,7 +514,7 @@ const DmuxApp = ({ panesFile, projectName, sessionName, settingsFile, autoUpdate
477
514
  // Wait and check if prompt is gone
478
515
  await new Promise(resolve => setTimeout(resolve, 500));
479
516
  // Verify the prompt is gone
480
- const updatedContent = execSync(`tmux capture-pane -t '${paneInfo}' -p -S -10`, { encoding: 'utf-8', stdio: 'pipe' });
517
+ const updatedContent = capturePaneContent(paneInfo, 10);
481
518
  // If trust prompt is gone, check if we need to resend the Claude command
482
519
  const promptGone = !trustPromptPatterns.some(p => p.test(updatedContent));
483
520
  if (promptGone) {
@@ -551,6 +588,8 @@ const DmuxApp = ({ panesFile, projectName, sessionName, settingsFile, autoUpdate
551
588
  // Ignore if already set or fails
552
589
  }
553
590
  execSync(`tmux select-pane -t '${paneId}'`, { stdio: 'pipe' });
591
+ // Clear screen after jump to remove artifacts
592
+ clearScreen();
554
593
  setStatusMessage('Jumped to pane');
555
594
  setTimeout(() => setStatusMessage(''), 2000);
556
595
  }
@@ -634,6 +673,9 @@ const DmuxApp = ({ panesFile, projectName, sessionName, settingsFile, autoUpdate
634
673
  // Update handling moved to useAutoUpdater
635
674
  // Helper function to clear screen artifacts
636
675
  const clearScreen = () => {
676
+ // CRITICAL: Force Ink to re-render FIRST, before clearing
677
+ // This prevents blank screen by ensuring React starts rendering immediately
678
+ setForceRepaintTrigger(prev => prev + 1);
637
679
  // Multiple clearing strategies to prevent artifacts
638
680
  // 1. Clear screen with ANSI codes
639
681
  process.stdout.write('\x1b[2J\x1b[H');
@@ -647,12 +689,6 @@ const DmuxApp = ({ panesFile, projectName, sessionName, settingsFile, autoUpdate
647
689
  execSync('tmux refresh-client', { stdio: 'pipe' });
648
690
  }
649
691
  catch { }
650
- // 4. Force Ink to repaint after clearing with a delay
651
- // This prevents the blank screen bug by ensuring Ink re-renders
652
- // after the terminal has processed the clear operations
653
- setTimeout(() => {
654
- setForceRepaintTrigger(prev => prev + 1);
655
- }, 200);
656
692
  };
657
693
  // Cleanup function for exit
658
694
  const cleanExit = () => {
@@ -710,7 +746,6 @@ const DmuxApp = ({ panesFile, projectName, sessionName, settingsFile, autoUpdate
710
746
  setKebabMenuPaneIndex(null);
711
747
  setKebabMenuOption(0);
712
748
  setKebabMenuActions([]);
713
- clearScreen();
714
749
  return;
715
750
  }
716
751
  else if (key.upArrow) {
@@ -724,7 +759,6 @@ const DmuxApp = ({ panesFile, projectName, sessionName, settingsFile, autoUpdate
724
759
  else if (key.return) {
725
760
  // Execute the selected menu action
726
761
  setShowKebabMenu(false);
727
- clearScreen();
728
762
  const selectedAction = availableActions[kebabMenuOption];
729
763
  if (selectedAction) {
730
764
  // Use the action system to execute
@@ -753,6 +787,173 @@ const DmuxApp = ({ panesFile, projectName, sessionName, settingsFile, autoUpdate
753
787
  }
754
788
  return;
755
789
  }
790
+ // Handle hooks dialog
791
+ if (showHooksDialog) {
792
+ if (key.escape) {
793
+ setShowHooksDialog(false);
794
+ setHooksSelectedIndex(0);
795
+ // Go back to settings dialog
796
+ setShowSettingsDialog(true);
797
+ setSettingsMode('list');
798
+ return;
799
+ }
800
+ else if (key.upArrow) {
801
+ setHooksSelectedIndex(Math.max(0, hooksSelectedIndex - 1));
802
+ return;
803
+ }
804
+ else if (key.downArrow) {
805
+ setHooksSelectedIndex(Math.min(hooksData.length - 1, hooksSelectedIndex + 1));
806
+ return;
807
+ }
808
+ else if (input === 'e') {
809
+ // Edit hooks using an agent
810
+ setShowHooksDialog(false);
811
+ setHooksSelectedIndex(0);
812
+ const prompt = "I would like to edit my dmux hooks in .dmux-hooks, please read the instructions in there and ask me what I want to edit";
813
+ setPendingPrompt(prompt);
814
+ setNewPanePrompt(prompt);
815
+ // Choose agent
816
+ const agents = availableAgents;
817
+ if (agents.length === 0) {
818
+ createNewPaneHook(prompt);
819
+ }
820
+ else if (agents.length === 1) {
821
+ createNewPaneHook(prompt, agents[0]);
822
+ }
823
+ else {
824
+ setShowAgentChoiceDialog(true);
825
+ setAgentChoice(agentChoice || 'claude');
826
+ }
827
+ return;
828
+ }
829
+ return;
830
+ }
831
+ // Handle settings dialog
832
+ if (showSettingsDialog) {
833
+ if (key.escape) {
834
+ if (settingsMode === 'list') {
835
+ // Close settings dialog
836
+ setShowSettingsDialog(false);
837
+ setSettingsMode('list');
838
+ setSettingsSelectedIndex(0);
839
+ setSettingsEditingKey(undefined);
840
+ }
841
+ else {
842
+ // Go back to list
843
+ setSettingsMode('list');
844
+ setSettingsEditingKey(undefined);
845
+ setSettingsEditingValueIndex(0);
846
+ setSettingsScopeIndex(0);
847
+ }
848
+ return;
849
+ }
850
+ else if (key.upArrow) {
851
+ if (settingsMode === 'list') {
852
+ setSettingsSelectedIndex(Math.max(0, settingsSelectedIndex - 1));
853
+ }
854
+ else if (settingsMode === 'edit') {
855
+ const currentDef = SETTING_DEFINITIONS[settingsSelectedIndex];
856
+ const maxIndex = currentDef.type === 'boolean' ? 1 : (currentDef.options?.length || 1) - 1;
857
+ setSettingsEditingValueIndex(Math.max(0, settingsEditingValueIndex - 1));
858
+ }
859
+ else if (settingsMode === 'scope') {
860
+ setSettingsScopeIndex(Math.max(0, settingsScopeIndex - 1));
861
+ }
862
+ return;
863
+ }
864
+ else if (key.downArrow) {
865
+ if (settingsMode === 'list') {
866
+ setSettingsSelectedIndex(Math.min(SETTING_DEFINITIONS.length - 1, settingsSelectedIndex + 1));
867
+ }
868
+ else if (settingsMode === 'edit') {
869
+ const currentDef = SETTING_DEFINITIONS[settingsSelectedIndex];
870
+ const maxIndex = currentDef.type === 'boolean' ? 1 : (currentDef.options?.length || 1) - 1;
871
+ setSettingsEditingValueIndex(Math.min(maxIndex, settingsEditingValueIndex + 1));
872
+ }
873
+ else if (settingsMode === 'scope') {
874
+ setSettingsScopeIndex(Math.min(1, settingsScopeIndex + 1));
875
+ }
876
+ return;
877
+ }
878
+ else if (key.return) {
879
+ if (settingsMode === 'list') {
880
+ const currentDef = SETTING_DEFINITIONS[settingsSelectedIndex];
881
+ // Handle action type - trigger the action instead of editing
882
+ if (currentDef.type === 'action') {
883
+ if (currentDef.key === 'hooks') {
884
+ // Show hooks dialog
885
+ setShowSettingsDialog(false);
886
+ const { hasHook } = await import('./utils/hooks.js');
887
+ const allHookTypes = [
888
+ 'before_pane_create',
889
+ 'pane_created',
890
+ 'worktree_created',
891
+ 'before_pane_close',
892
+ 'pane_closed',
893
+ 'before_worktree_remove',
894
+ 'worktree_removed',
895
+ 'pre_merge',
896
+ 'post_merge',
897
+ 'run_test',
898
+ 'run_dev',
899
+ ];
900
+ const hooks = allHookTypes.map(hookName => ({
901
+ name: hookName,
902
+ active: hasHook(projectRoot || process.cwd(), hookName)
903
+ }));
904
+ setHooksData(hooks);
905
+ setShowHooksDialog(true);
906
+ setHooksSelectedIndex(0);
907
+ }
908
+ return;
909
+ }
910
+ // Enter edit mode for regular settings
911
+ setSettingsEditingKey(currentDef.key);
912
+ setSettingsMode('edit');
913
+ // Set initial value index based on current setting
914
+ const currentValue = settingsManager.getSetting(currentDef.key);
915
+ if (currentDef.type === 'boolean') {
916
+ setSettingsEditingValueIndex(currentValue ? 0 : 1);
917
+ }
918
+ else if (currentDef.type === 'select' && currentDef.options) {
919
+ const optIndex = currentDef.options.findIndex(o => o.value === currentValue);
920
+ setSettingsEditingValueIndex(Math.max(0, optIndex));
921
+ }
922
+ }
923
+ else if (settingsMode === 'edit') {
924
+ // Go to scope selection
925
+ setSettingsMode('scope');
926
+ setSettingsScopeIndex(0);
927
+ }
928
+ else if (settingsMode === 'scope') {
929
+ // Save the setting
930
+ const currentDef = SETTING_DEFINITIONS[settingsSelectedIndex];
931
+ const scope = settingsScopeIndex === 0 ? 'global' : 'project';
932
+ // Only save if this is not an action type (actions don't have values)
933
+ if (currentDef.type !== 'action') {
934
+ // Calculate the new value
935
+ let newValue;
936
+ if (currentDef.type === 'boolean') {
937
+ newValue = settingsEditingValueIndex === 0;
938
+ }
939
+ else if (currentDef.type === 'select' && currentDef.options) {
940
+ newValue = currentDef.options[settingsEditingValueIndex]?.value || '';
941
+ }
942
+ // Update the setting - cast key to proper type since we know it's not an action
943
+ settingsManager.updateSetting(currentDef.key, newValue, scope);
944
+ }
945
+ // Reset to list view
946
+ setSettingsMode('list');
947
+ setSettingsEditingKey(undefined);
948
+ setSettingsEditingValueIndex(0);
949
+ setSettingsScopeIndex(0);
950
+ setStatusMessage(`Setting saved (${scope})`);
951
+ setTimeout(() => setStatusMessage(''), 2000);
952
+ }
953
+ return;
954
+ }
955
+ return;
956
+ }
756
957
  // Handle action system confirm dialog
757
958
  if (actionSystem.actionState.showConfirmDialog) {
758
959
  if (key.escape) {
@@ -911,7 +1112,7 @@ const DmuxApp = ({ panesFile, projectName, sessionName, settingsFile, autoUpdate
911
1112
  const promptValue = pendingPrompt;
912
1113
  setShowAgentChoiceDialog(false);
913
1114
  setPendingPrompt('');
914
- await createNewPane(promptValue, chosen);
1115
+ await createNewPaneHook(promptValue, chosen);
915
1116
  setNewPanePrompt('');
916
1117
  }
917
1118
  return;
@@ -964,10 +1165,6 @@ const DmuxApp = ({ panesFile, projectName, sessionName, settingsFile, autoUpdate
964
1165
  setShowNewPaneDialog(false);
965
1166
  setNewPanePrompt('');
966
1167
  }
967
- else if (key.ctrl && input === 'o') {
968
- // Open in external editor
969
- openEditor2(newPanePrompt, setNewPanePrompt);
970
- }
971
1168
  // TextInput handles other input events
972
1169
  return;
973
1170
  }
@@ -1000,6 +1197,12 @@ const DmuxApp = ({ panesFile, projectName, sessionName, settingsFile, autoUpdate
1000
1197
  setKebabMenuPaneIndex(selectedIndex);
1001
1198
  setKebabMenuOption(0);
1002
1199
  }
1200
+ else if (input === 's') {
1201
+ // Open settings dialog
1202
+ setShowSettingsDialog(true);
1203
+ setSettingsMode('list');
1204
+ setSettingsSelectedIndex(0);
1205
+ }
1003
1206
  else if (input === 'q') {
1004
1207
  cleanExit();
1005
1208
  }
@@ -1035,14 +1238,20 @@ const DmuxApp = ({ panesFile, projectName, sessionName, settingsFile, autoUpdate
1035
1238
  }
1036
1239
  else if (input === 'j' && selectedIndex < panes.length) {
1037
1240
  // Jump to pane (NEW: using action system)
1241
+ StateManager.getInstance().setDebugMessage(`Jumping to pane: ${panes[selectedIndex].slug}`);
1242
+ setTimeout(() => StateManager.getInstance().setDebugMessage(''), 2000);
1038
1243
  actionSystem.executeAction(PaneAction.VIEW, panes[selectedIndex]);
1039
1244
  }
1040
1245
  else if (input === 'x' && selectedIndex < panes.length) {
1041
1246
  // Close pane (NEW: using action system)
1247
+ StateManager.getInstance().setDebugMessage(`Closing pane: ${panes[selectedIndex].slug}`);
1248
+ setTimeout(() => StateManager.getInstance().setDebugMessage(''), 2000);
1042
1249
  actionSystem.executeAction(PaneAction.CLOSE, panes[selectedIndex]);
1043
1250
  }
1044
1251
  else if (key.return && selectedIndex < panes.length) {
1045
1252
  // Jump to pane (NEW: using action system)
1253
+ StateManager.getInstance().setDebugMessage(`Jumping to pane: ${panes[selectedIndex].slug}`);
1254
+ setTimeout(() => StateManager.getInstance().setDebugMessage(''), 2000);
1046
1255
  actionSystem.executeAction(PaneAction.VIEW, panes[selectedIndex]);
1047
1256
  }
1048
1257
  });
@@ -1056,6 +1265,8 @@ const DmuxApp = ({ panesFile, projectName, sessionName, settingsFile, autoUpdate
1056
1265
  React.createElement(Text, { dimColor: true }, "Press ESC to return to pane list"))));
1057
1266
  }
1058
1267
  return (React.createElement(Box, { flexDirection: "column" },
1268
+ showRepaintSpinner && (React.createElement(Box, { marginTop: -10, marginLeft: -100 },
1269
+ React.createElement(Text, null, "\u27F3"))),
1059
1270
  React.createElement(PanesGrid, { panes: panes, selectedIndex: selectedIndex, isLoading: isLoading, showNewPaneDialog: showNewPaneDialog, agentStatuses: agentStatuses, kebabMenuPaneIndex: kebabMenuPaneIndex ?? undefined }),
1060
1271
  isLoading && (React.createElement(LoadingIndicator, null)),
1061
1272
  showNewPaneDialog && !showAgentChoiceDialog && (React.createElement(NewPaneDialog, { value: newPanePrompt, onChange: setNewPanePrompt, onSubmit: (value) => {
@@ -1084,6 +1295,8 @@ const DmuxApp = ({ panesFile, projectName, sessionName, settingsFile, autoUpdate
1084
1295
  showCommandPrompt && (React.createElement(CommandPromptDialog, { type: showCommandPrompt, value: commandInput, onChange: setCommandInput })),
1085
1296
  showFileCopyPrompt && (React.createElement(FileCopyPrompt, null)),
1086
1297
  showKebabMenu && kebabMenuPaneIndex !== null && panes[kebabMenuPaneIndex] && (React.createElement(KebabMenu, { selectedOption: kebabMenuOption, actions: kebabMenuActions, paneName: panes[kebabMenuPaneIndex].slug })),
1298
+ showSettingsDialog && (React.createElement(SettingsDialog, { settings: settingsManager.getSettings(), globalSettings: settingsManager.getGlobalSettings(), projectSettings: settingsManager.getProjectSettings(), settingDefinitions: SETTING_DEFINITIONS, selectedIndex: settingsSelectedIndex, mode: settingsMode, editingKey: settingsEditingKey, editingValueIndex: settingsEditingValueIndex, scopeIndex: settingsScopeIndex })),
1299
+ showHooksDialog && (React.createElement(HooksDialog, { hooks: hooksData, selectedIndex: hooksSelectedIndex })),
1087
1300
  actionSystem.actionState.showConfirmDialog && (React.createElement(ActionConfirmDialog, { key: "confirm-dialog", title: actionSystem.actionState.confirmTitle, message: actionSystem.actionState.confirmMessage, yesLabel: actionSystem.actionState.confirmYesLabel, noLabel: actionSystem.actionState.confirmNoLabel, selectedIndex: actionSystem.actionState.confirmSelectedIndex })),
1088
1301
  actionSystem.actionState.showChoiceDialog && (React.createElement(ActionChoiceDialog, { key: "choice-dialog", title: actionSystem.actionState.choiceTitle, message: actionSystem.actionState.choiceMessage, options: actionSystem.actionState.choiceOptions, selectedIndex: actionSystem.actionState.choiceSelectedIndex })),
1089
1302
  actionSystem.actionState.showInputDialog && (React.createElement(ActionInputDialog, { key: "input-dialog", title: actionSystem.actionState.inputTitle, message: actionSystem.actionState.inputMessage, placeholder: actionSystem.actionState.inputPlaceholder, value: actionSystem.actionState.inputValue, onValueChange: (value) => {
@@ -1111,11 +1324,17 @@ const DmuxApp = ({ panesFile, projectName, sessionName, settingsFile, autoUpdate
1111
1324
  return `Grid: ${cols} cols × ${rows} rows | Selected: row ${pos.row}, col ${pos.col} | Terminal: ${terminalWidth}w`;
1112
1325
  })() }),
1113
1326
  React.createElement(Text, { dimColor: true },
1327
+ updateAvailable && updateInfo && (React.createElement(Text, { color: "red", bold: true }, "Update available: npm i -g dmux@latest ")),
1114
1328
  "v",
1115
1329
  packageJson.version,
1116
- updateAvailable && updateInfo && (React.createElement(Text, { color: "yellow" },
1117
- " \u2022 Update available: ",
1118
- updateInfo.latestVersion)))));
1330
+ serverPort && serverPort > 0 && (React.createElement(Text, { dimColor: true },
1331
+ " \u2022 ",
1332
+ React.createElement(Text, { color: "cyan" },
1333
+ "http://127.0.0.1:",
1334
+ serverPort))),
1335
+ debugMessage && (React.createElement(Text, { dimColor: true },
1336
+ " \u2022 ",
1337
+ debugMessage)))));
1119
1338
  };
1120
1339
  export default DmuxApp;
1121
1340
  //# sourceMappingURL=DmuxApp.js.map