dmux 3.1.1 → 3.3.0
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/dist/DmuxApp.d.ts +2 -2
- package/dist/DmuxApp.d.ts.map +1 -1
- package/dist/DmuxApp.js +405 -1134
- package/dist/DmuxApp.js.map +1 -1
- package/dist/actions/implementations/closeAction.d.ts +10 -0
- package/dist/actions/implementations/closeAction.d.ts.map +1 -0
- package/dist/actions/implementations/closeAction.js +197 -0
- package/dist/actions/implementations/closeAction.js.map +1 -0
- package/dist/actions/implementations/copyPathAction.d.ts +10 -0
- package/dist/actions/implementations/copyPathAction.d.ts.map +1 -0
- package/dist/actions/implementations/copyPathAction.js +34 -0
- package/dist/actions/implementations/copyPathAction.js.map +1 -0
- package/dist/actions/implementations/duplicateAction.d.ts +10 -0
- package/dist/actions/implementations/duplicateAction.d.ts.map +1 -0
- package/dist/actions/implementations/duplicateAction.js +25 -0
- package/dist/actions/implementations/duplicateAction.js.map +1 -0
- package/dist/actions/implementations/index.d.ts +14 -0
- package/dist/actions/implementations/index.d.ts.map +1 -0
- package/dist/actions/implementations/index.js +14 -0
- package/dist/actions/implementations/index.js.map +1 -0
- package/dist/actions/implementations/mergeAction.d.ts +14 -0
- package/dist/actions/implementations/mergeAction.d.ts.map +1 -0
- package/dist/actions/implementations/mergeAction.js +84 -0
- package/dist/actions/implementations/mergeAction.js.map +1 -0
- package/dist/actions/implementations/openInEditorAction.d.ts +12 -0
- package/dist/actions/implementations/openInEditorAction.d.ts.map +1 -0
- package/dist/actions/implementations/openInEditorAction.js +33 -0
- package/dist/actions/implementations/openInEditorAction.js.map +1 -0
- package/dist/actions/implementations/renameAction.d.ts +13 -0
- package/dist/actions/implementations/renameAction.d.ts.map +1 -0
- package/dist/actions/implementations/renameAction.js +18 -0
- package/dist/actions/implementations/renameAction.js.map +1 -0
- package/dist/actions/implementations/toggleAutopilotAction.d.ts +10 -0
- package/dist/actions/implementations/toggleAutopilotAction.d.ts.map +1 -0
- package/dist/actions/implementations/toggleAutopilotAction.js +33 -0
- package/dist/actions/implementations/toggleAutopilotAction.js.map +1 -0
- package/dist/actions/implementations/viewAction.d.ts +10 -0
- package/dist/actions/implementations/viewAction.d.ts.map +1 -0
- package/dist/actions/implementations/viewAction.js +26 -0
- package/dist/actions/implementations/viewAction.js.map +1 -0
- package/dist/actions/merge/commitMessageHandler.d.ts +27 -0
- package/dist/actions/merge/commitMessageHandler.d.ts.map +1 -0
- package/dist/actions/merge/commitMessageHandler.js +131 -0
- package/dist/actions/merge/commitMessageHandler.js.map +1 -0
- package/dist/actions/merge/conflictResolution.d.ts +13 -0
- package/dist/actions/merge/conflictResolution.d.ts.map +1 -0
- package/dist/actions/merge/conflictResolution.js +134 -0
- package/dist/actions/merge/conflictResolution.js.map +1 -0
- package/dist/actions/merge/issueHandlers/index.d.ts +11 -0
- package/dist/actions/merge/issueHandlers/index.d.ts.map +1 -0
- package/dist/actions/merge/issueHandlers/index.js +8 -0
- package/dist/actions/merge/issueHandlers/index.js.map +1 -0
- package/dist/actions/merge/issueHandlers/mainDirtyHandler.d.ts +13 -0
- package/dist/actions/merge/issueHandlers/mainDirtyHandler.d.ts.map +1 -0
- package/dist/actions/merge/issueHandlers/mainDirtyHandler.js +72 -0
- package/dist/actions/merge/issueHandlers/mainDirtyHandler.js.map +1 -0
- package/dist/actions/merge/issueHandlers/mergeConflictHandler.d.ts +13 -0
- package/dist/actions/merge/issueHandlers/mergeConflictHandler.d.ts.map +1 -0
- package/dist/actions/merge/issueHandlers/mergeConflictHandler.js +52 -0
- package/dist/actions/merge/issueHandlers/mergeConflictHandler.js.map +1 -0
- package/dist/actions/merge/issueHandlers/nothingToMergeHandler.d.ts +7 -0
- package/dist/actions/merge/issueHandlers/nothingToMergeHandler.d.ts.map +1 -0
- package/dist/actions/merge/issueHandlers/nothingToMergeHandler.js +12 -0
- package/dist/actions/merge/issueHandlers/nothingToMergeHandler.js.map +1 -0
- package/dist/actions/merge/issueHandlers/worktreeUncommittedHandler.d.ts +13 -0
- package/dist/actions/merge/issueHandlers/worktreeUncommittedHandler.d.ts.map +1 -0
- package/dist/actions/merge/issueHandlers/worktreeUncommittedHandler.js +49 -0
- package/dist/actions/merge/issueHandlers/worktreeUncommittedHandler.js.map +1 -0
- package/dist/actions/merge/mergeExecution.d.ts +22 -0
- package/dist/actions/merge/mergeExecution.d.ts.map +1 -0
- package/dist/actions/merge/mergeExecution.js +180 -0
- package/dist/actions/merge/mergeExecution.js.map +1 -0
- package/dist/actions/paneActions.d.ts +3 -40
- package/dist/actions/paneActions.d.ts.map +1 -1
- package/dist/actions/paneActions.js +4 -981
- package/dist/actions/paneActions.js.map +1 -1
- package/dist/actions/types.d.ts +2 -0
- package/dist/actions/types.d.ts.map +1 -1
- package/dist/actions/types.js +1 -0
- package/dist/actions/types.js.map +1 -1
- package/dist/components/{ActionChoiceDialog.d.ts → dialogs/ActionChoiceDialog.d.ts} +1 -1
- package/dist/components/dialogs/ActionChoiceDialog.d.ts.map +1 -0
- package/dist/components/dialogs/ActionChoiceDialog.js.map +1 -0
- package/dist/components/dialogs/ActionConfirmDialog.d.ts.map +1 -0
- package/dist/components/dialogs/ActionConfirmDialog.js.map +1 -0
- package/dist/components/dialogs/ActionInputDialog.d.ts.map +1 -0
- package/dist/components/{ActionInputDialog.js → dialogs/ActionInputDialog.js} +4 -3
- package/dist/components/dialogs/ActionInputDialog.js.map +1 -0
- package/dist/components/dialogs/ActionProgressDialog.d.ts.map +1 -0
- package/dist/components/dialogs/ActionProgressDialog.js.map +1 -0
- package/dist/components/dialogs/AgentChoiceDialog.d.ts.map +1 -0
- package/dist/components/dialogs/AgentChoiceDialog.js.map +1 -0
- package/dist/components/{CloseOptionsDialog.d.ts → dialogs/CloseOptionsDialog.d.ts} +1 -1
- package/dist/components/dialogs/CloseOptionsDialog.d.ts.map +1 -0
- package/dist/components/dialogs/CloseOptionsDialog.js.map +1 -0
- package/dist/components/dialogs/CommandPromptDialog.d.ts.map +1 -0
- package/dist/components/{CommandPromptDialog.js → dialogs/CommandPromptDialog.js} +1 -1
- package/dist/components/dialogs/CommandPromptDialog.js.map +1 -0
- package/dist/components/dialogs/DialogBox.d.ts +16 -0
- package/dist/components/dialogs/DialogBox.d.ts.map +1 -0
- package/dist/components/dialogs/DialogBox.js +12 -0
- package/dist/components/dialogs/DialogBox.js.map +1 -0
- package/dist/components/dialogs/HooksDialog.d.ts.map +1 -0
- package/dist/components/dialogs/HooksDialog.js.map +1 -0
- package/dist/components/{MergeConfirmationDialog.d.ts → dialogs/MergeConfirmationDialog.d.ts} +1 -1
- package/dist/components/dialogs/MergeConfirmationDialog.d.ts.map +1 -0
- package/dist/components/dialogs/MergeConfirmationDialog.js.map +1 -0
- package/dist/components/{SettingsDialog.d.ts → dialogs/SettingsDialog.d.ts} +1 -1
- package/dist/components/dialogs/SettingsDialog.d.ts.map +1 -0
- package/dist/components/dialogs/SettingsDialog.js.map +1 -0
- package/dist/components/dialogs/UpdateDialog.d.ts.map +1 -0
- package/dist/components/dialogs/UpdateDialog.js.map +1 -0
- package/dist/components/indicators/CreatingIndicator.d.ts.map +1 -0
- package/dist/components/indicators/CreatingIndicator.js.map +1 -0
- package/dist/components/indicators/LoadingIndicator.d.ts.map +1 -0
- package/dist/components/indicators/LoadingIndicator.js.map +1 -0
- package/dist/components/indicators/RunningIndicator.d.ts.map +1 -0
- package/dist/components/indicators/RunningIndicator.js.map +1 -0
- package/dist/components/indicators/Spinner.d.ts.map +1 -0
- package/dist/components/indicators/Spinner.js.map +1 -0
- package/dist/components/indicators/UpdatingIndicator.d.ts.map +1 -0
- package/dist/components/indicators/UpdatingIndicator.js.map +1 -0
- package/dist/components/indicators/index.d.ts +6 -0
- package/dist/components/indicators/index.d.ts.map +1 -0
- package/dist/components/indicators/index.js +6 -0
- package/dist/components/indicators/index.js.map +1 -0
- package/dist/components/inputs/CleanTextInput.d.ts +19 -0
- package/dist/components/inputs/CleanTextInput.d.ts.map +1 -0
- package/dist/{CleanTextInput.js → components/inputs/CleanTextInput.js} +98 -160
- package/dist/components/inputs/CleanTextInput.js.map +1 -0
- package/dist/components/inputs/StyledTextInput.d.ts.map +1 -0
- package/dist/components/inputs/StyledTextInput.js.map +1 -0
- package/dist/components/inputs/index.d.ts +3 -0
- package/dist/components/inputs/index.d.ts.map +1 -0
- package/dist/components/inputs/index.js +3 -0
- package/dist/components/inputs/index.js.map +1 -0
- package/dist/components/{KebabMenu.d.ts → panes/KebabMenu.d.ts} +1 -1
- package/dist/components/panes/KebabMenu.d.ts.map +1 -0
- package/dist/components/panes/KebabMenu.js.map +1 -0
- package/dist/components/panes/MergePane.d.ts.map +1 -0
- package/dist/{MergePane.js → components/panes/MergePane.js} +1 -1
- package/dist/components/panes/MergePane.js.map +1 -0
- package/dist/components/{PaneCard.d.ts → panes/PaneCard.d.ts} +4 -2
- package/dist/components/panes/PaneCard.d.ts.map +1 -0
- package/dist/components/panes/PaneCard.js +55 -0
- package/dist/components/panes/PaneCard.js.map +1 -0
- package/dist/components/panes/PanesGrid.d.ts +12 -0
- package/dist/components/panes/PanesGrid.d.ts.map +1 -0
- package/dist/components/panes/PanesGrid.js +49 -0
- package/dist/components/panes/PanesGrid.js.map +1 -0
- package/dist/components/panes/index.d.ts +5 -0
- package/dist/components/panes/index.d.ts.map +1 -0
- package/dist/components/panes/index.js +5 -0
- package/dist/components/panes/index.js.map +1 -0
- package/dist/components/popups/agentChoicePopup.d.ts +7 -0
- package/dist/components/popups/agentChoicePopup.d.ts.map +1 -0
- package/dist/components/popups/agentChoicePopup.js +74 -0
- package/dist/components/popups/agentChoicePopup.js.map +1 -0
- package/dist/components/popups/choicePopup.d.ts +7 -0
- package/dist/components/popups/choicePopup.d.ts.map +1 -0
- package/dist/components/popups/choicePopup.js +64 -0
- package/dist/components/popups/choicePopup.js.map +1 -0
- package/dist/components/popups/config.d.ts +40 -0
- package/dist/components/popups/config.d.ts.map +1 -0
- package/dist/components/popups/config.js +40 -0
- package/dist/components/popups/config.js.map +1 -0
- package/dist/components/popups/confirmPopup.d.ts +7 -0
- package/dist/components/popups/confirmPopup.d.ts.map +1 -0
- package/dist/components/popups/confirmPopup.js +71 -0
- package/dist/components/popups/confirmPopup.js.map +1 -0
- package/dist/components/popups/hooksPopup.d.ts +7 -0
- package/dist/components/popups/hooksPopup.d.ts.map +1 -0
- package/dist/components/popups/hooksPopup.js +71 -0
- package/dist/components/popups/hooksPopup.js.map +1 -0
- package/dist/components/popups/inputPopup.d.ts +7 -0
- package/dist/components/popups/inputPopup.d.ts.map +1 -0
- package/dist/components/popups/inputPopup.js +47 -0
- package/dist/components/popups/inputPopup.js.map +1 -0
- package/dist/components/popups/kebabMenuPopup.d.ts +7 -0
- package/dist/components/popups/kebabMenuPopup.d.ts.map +1 -0
- package/dist/components/popups/kebabMenuPopup.js +52 -0
- package/dist/components/popups/kebabMenuPopup.js.map +1 -0
- package/dist/components/popups/logsPopup.d.ts +12 -0
- package/dist/components/popups/logsPopup.d.ts.map +1 -0
- package/dist/components/popups/logsPopup.js +372 -0
- package/dist/components/popups/logsPopup.js.map +1 -0
- package/dist/components/popups/mergePopup.d.ts +7 -0
- package/dist/components/popups/mergePopup.d.ts.map +1 -0
- package/dist/components/popups/mergePopup.js +310 -0
- package/dist/components/popups/mergePopup.js.map +1 -0
- package/dist/components/popups/newPanePopup.d.ts +7 -0
- package/dist/components/popups/newPanePopup.d.ts.map +1 -0
- package/dist/components/popups/newPanePopup.js +234 -0
- package/dist/components/popups/newPanePopup.js.map +1 -0
- package/dist/components/popups/progressPopup.d.ts +8 -0
- package/dist/components/popups/progressPopup.d.ts.map +1 -0
- package/dist/components/popups/progressPopup.js +53 -0
- package/dist/components/popups/progressPopup.js.map +1 -0
- package/dist/components/popups/remotePopup.d.ts +6 -0
- package/dist/components/popups/remotePopup.d.ts.map +1 -0
- package/dist/components/popups/remotePopup.js +166 -0
- package/dist/components/popups/remotePopup.js.map +1 -0
- package/dist/components/popups/settingsPopup.d.ts +7 -0
- package/dist/components/popups/settingsPopup.d.ts.map +1 -0
- package/dist/components/popups/settingsPopup.js +212 -0
- package/dist/components/popups/settingsPopup.js.map +1 -0
- package/dist/components/popups/shared/FileList.d.ts +13 -0
- package/dist/components/popups/shared/FileList.d.ts.map +1 -0
- package/dist/components/popups/shared/FileList.js +61 -0
- package/dist/components/popups/shared/FileList.js.map +1 -0
- package/dist/components/popups/shared/PopupContainer.d.ts +14 -0
- package/dist/components/popups/shared/PopupContainer.d.ts.map +1 -0
- package/dist/components/popups/shared/PopupContainer.js +15 -0
- package/dist/components/popups/shared/PopupContainer.js.map +1 -0
- package/dist/components/popups/shared/PopupInputBox.d.ts +11 -0
- package/dist/components/popups/shared/PopupInputBox.d.ts.map +1 -0
- package/dist/components/popups/shared/PopupInputBox.js +10 -0
- package/dist/components/popups/shared/PopupInputBox.js.map +1 -0
- package/dist/components/popups/shared/PopupWrapper.d.ts +37 -0
- package/dist/components/popups/shared/PopupWrapper.d.ts.map +1 -0
- package/dist/components/popups/shared/PopupWrapper.js +88 -0
- package/dist/components/popups/shared/PopupWrapper.js.map +1 -0
- package/dist/components/popups/shared/index.d.ts +8 -0
- package/dist/components/popups/shared/index.d.ts.map +1 -0
- package/dist/components/popups/shared/index.js +8 -0
- package/dist/components/popups/shared/index.js.map +1 -0
- package/dist/components/popups/shortcutsPopup.d.ts +6 -0
- package/dist/components/popups/shortcutsPopup.d.ts.map +1 -0
- package/dist/components/popups/shortcutsPopup.js +74 -0
- package/dist/components/popups/shortcutsPopup.js.map +1 -0
- package/dist/components/popups/templates/SimpleInputPopup.d.ts +15 -0
- package/dist/components/popups/templates/SimpleInputPopup.d.ts.map +1 -0
- package/dist/components/popups/templates/SimpleInputPopup.js +28 -0
- package/dist/components/popups/templates/SimpleInputPopup.js.map +1 -0
- package/dist/components/ui/FileCopyPrompt.d.ts.map +1 -0
- package/dist/components/ui/FileCopyPrompt.js.map +1 -0
- package/dist/components/ui/FooterHelp.d.ts +19 -0
- package/dist/components/ui/FooterHelp.d.ts.map +1 -0
- package/dist/components/ui/FooterHelp.js +55 -0
- package/dist/components/ui/FooterHelp.js.map +1 -0
- package/dist/components/ui/QRCode.d.ts.map +1 -0
- package/dist/components/ui/QRCode.js.map +1 -0
- package/dist/components/ui/index.d.ts +4 -0
- package/dist/components/ui/index.d.ts.map +1 -0
- package/dist/components/ui/index.js +4 -0
- package/dist/components/ui/index.js.map +1 -0
- package/dist/constants/timing.d.ts +22 -0
- package/dist/constants/timing.d.ts.map +1 -0
- package/dist/constants/timing.js +26 -0
- package/dist/constants/timing.js.map +1 -0
- package/dist/dashboard.js +1 -1
- package/dist/hooks/useActionSystem.d.ts +18 -4
- package/dist/hooks/useActionSystem.d.ts.map +1 -1
- package/dist/hooks/useActionSystem.js +125 -30
- package/dist/hooks/useActionSystem.js.map +1 -1
- package/dist/hooks/useDebugInfo.d.ts +11 -0
- package/dist/hooks/useDebugInfo.d.ts.map +1 -0
- package/dist/hooks/useDebugInfo.js +34 -0
- package/dist/hooks/useDebugInfo.js.map +1 -0
- package/dist/hooks/useDialogState.d.ts +22 -0
- package/dist/hooks/useDialogState.d.ts.map +1 -0
- package/dist/hooks/useDialogState.js +62 -0
- package/dist/hooks/useDialogState.js.map +1 -0
- package/dist/hooks/useInputHandling.d.ts +60 -0
- package/dist/hooks/useInputHandling.d.ts.map +1 -0
- package/dist/hooks/useInputHandling.js +280 -0
- package/dist/hooks/useInputHandling.js.map +1 -0
- package/dist/hooks/useLayoutManagement.d.ts +12 -0
- package/dist/hooks/useLayoutManagement.d.ts.map +1 -0
- package/dist/hooks/useLayoutManagement.js +58 -0
- package/dist/hooks/useLayoutManagement.js.map +1 -0
- package/dist/hooks/useNavigation.js +1 -1
- package/dist/hooks/useNavigation.js.map +1 -1
- package/dist/hooks/usePaneCreation.d.ts +1 -2
- package/dist/hooks/usePaneCreation.d.ts.map +1 -1
- package/dist/hooks/usePaneCreation.js +17 -36
- package/dist/hooks/usePaneCreation.js.map +1 -1
- package/dist/hooks/usePaneLoading.d.ts +45 -0
- package/dist/hooks/usePaneLoading.d.ts.map +1 -0
- package/dist/hooks/usePaneLoading.js +188 -0
- package/dist/hooks/usePaneLoading.js.map +1 -0
- package/dist/hooks/usePaneRunner.d.ts.map +1 -1
- package/dist/hooks/usePaneRunner.js +16 -8
- package/dist/hooks/usePaneRunner.js.map +1 -1
- package/dist/hooks/usePaneSync.d.ts +34 -0
- package/dist/hooks/usePaneSync.d.ts.map +1 -0
- package/dist/hooks/usePaneSync.js +182 -0
- package/dist/hooks/usePaneSync.js.map +1 -0
- package/dist/hooks/usePanes.d.ts.map +1 -1
- package/dist/hooks/usePanes.js +81 -258
- package/dist/hooks/usePanes.js.map +1 -1
- package/dist/hooks/useServices.d.ts +24 -0
- package/dist/hooks/useServices.d.ts.map +1 -0
- package/dist/hooks/useServices.js +39 -0
- package/dist/hooks/useServices.js.map +1 -0
- package/dist/hooks/useShellDetection.d.ts +10 -0
- package/dist/hooks/useShellDetection.d.ts.map +1 -0
- package/dist/hooks/useShellDetection.js +53 -0
- package/dist/hooks/useShellDetection.js.map +1 -0
- package/dist/hooks/useStatusMessages.d.ts +11 -0
- package/dist/hooks/useStatusMessages.d.ts.map +1 -0
- package/dist/hooks/useStatusMessages.js +32 -0
- package/dist/hooks/useStatusMessages.js.map +1 -0
- package/dist/hooks/useTemporaryStatus.d.ts +13 -0
- package/dist/hooks/useTemporaryStatus.d.ts.map +1 -0
- package/dist/hooks/useTemporaryStatus.js +30 -0
- package/dist/hooks/useTemporaryStatus.js.map +1 -0
- package/dist/hooks/useTerminalWidth.d.ts.map +1 -1
- package/dist/hooks/useTerminalWidth.js +7 -12
- package/dist/hooks/useTerminalWidth.js.map +1 -1
- package/dist/hooks/useTunnelManagement.d.ts +18 -0
- package/dist/hooks/useTunnelManagement.d.ts.map +1 -0
- package/dist/hooks/useTunnelManagement.js +55 -0
- package/dist/hooks/useTunnelManagement.js.map +1 -0
- package/dist/hooks/useWorktreeActions.d.ts.map +1 -1
- package/dist/hooks/useWorktreeActions.js +23 -24
- package/dist/hooks/useWorktreeActions.js.map +1 -1
- package/dist/index.js +279 -73
- package/dist/index.js.map +1 -1
- package/dist/layout/LayoutCalculator.d.ts +62 -0
- package/dist/layout/LayoutCalculator.d.ts.map +1 -0
- package/dist/layout/LayoutCalculator.js +143 -0
- package/dist/layout/LayoutCalculator.js.map +1 -0
- package/dist/layout/SpacerManager.d.ts +64 -0
- package/dist/layout/SpacerManager.d.ts.map +1 -0
- package/dist/layout/SpacerManager.js +148 -0
- package/dist/layout/SpacerManager.js.map +1 -0
- package/dist/layout/TmuxLayoutApplier.d.ts +59 -0
- package/dist/layout/TmuxLayoutApplier.d.ts.map +1 -0
- package/dist/layout/TmuxLayoutApplier.js +135 -0
- package/dist/layout/TmuxLayoutApplier.js.map +1 -0
- package/dist/panes/decorative-pane.d.ts +3 -0
- package/dist/panes/decorative-pane.d.ts.map +1 -0
- package/dist/panes/decorative-pane.js +136 -0
- package/dist/panes/decorative-pane.js.map +1 -0
- package/dist/panes/spacer-pane.d.ts +8 -0
- package/dist/panes/spacer-pane.d.ts.map +1 -0
- package/dist/panes/spacer-pane.js +40 -0
- package/dist/panes/spacer-pane.js.map +1 -0
- package/dist/server/embedded-assets.d.ts.map +1 -1
- package/dist/server/embedded-assets.js +849 -4752
- package/dist/server/embedded-assets.js.map +1 -1
- package/dist/server/index.js +1 -1
- package/dist/server/index.js.map +1 -1
- package/dist/server/routes/actionsRoutes.d.ts +2 -0
- package/dist/server/routes/actionsRoutes.d.ts.map +1 -0
- package/dist/server/routes/actionsRoutes.js +110 -0
- package/dist/server/routes/actionsRoutes.js.map +1 -0
- package/dist/server/routes/healthRoutes.d.ts +13 -0
- package/dist/server/routes/healthRoutes.d.ts.map +1 -0
- package/dist/server/routes/healthRoutes.js +70 -0
- package/dist/server/routes/healthRoutes.js.map +1 -0
- package/dist/server/routes/index.d.ts +8 -0
- package/dist/server/routes/index.d.ts.map +1 -0
- package/dist/server/routes/index.js +67 -0
- package/dist/server/routes/index.js.map +1 -0
- package/dist/server/routes/keysRoutes.d.ts +20 -0
- package/dist/server/routes/keysRoutes.d.ts.map +1 -0
- package/dist/server/routes/keysRoutes.js +111 -0
- package/dist/server/routes/keysRoutes.js.map +1 -0
- package/dist/server/routes/panesRoutes.d.ts +2 -0
- package/dist/server/routes/panesRoutes.d.ts.map +1 -0
- package/dist/server/routes/panesRoutes.js +373 -0
- package/dist/server/routes/panesRoutes.js.map +1 -0
- package/dist/server/routes/settingsRoutes.d.ts +94 -0
- package/dist/server/routes/settingsRoutes.d.ts.map +1 -0
- package/dist/server/routes/settingsRoutes.js +159 -0
- package/dist/server/routes/settingsRoutes.js.map +1 -0
- package/dist/server/routes/streamRoutes.d.ts +18 -0
- package/dist/server/routes/streamRoutes.d.ts.map +1 -0
- package/dist/server/routes/streamRoutes.js +87 -0
- package/dist/server/routes/streamRoutes.js.map +1 -0
- package/dist/server/routes/tunnelRoutes.d.ts +11 -0
- package/dist/server/routes/tunnelRoutes.d.ts.map +1 -0
- package/dist/server/routes/tunnelRoutes.js +28 -0
- package/dist/server/routes/tunnelRoutes.js.map +1 -0
- package/dist/server/routes.d.ts +16 -2
- package/dist/server/routes.d.ts.map +1 -1
- package/dist/server/routes.js +16 -811
- package/dist/server/routes.js.map +1 -1
- package/dist/{AutoUpdater.d.ts → services/AutoUpdater.d.ts} +1 -0
- package/dist/services/AutoUpdater.d.ts.map +1 -0
- package/dist/{AutoUpdater.js → services/AutoUpdater.js} +42 -9
- package/dist/services/AutoUpdater.js.map +1 -0
- package/dist/services/ConfigWatcher.d.ts.map +1 -1
- package/dist/services/ConfigWatcher.js +10 -3
- package/dist/services/ConfigWatcher.js.map +1 -1
- package/dist/services/LogService.d.ts +112 -0
- package/dist/services/LogService.d.ts.map +1 -0
- package/dist/services/LogService.js +252 -0
- package/dist/services/LogService.js.map +1 -0
- package/dist/services/PaneAnalyzer.d.ts.map +1 -0
- package/dist/{PaneAnalyzer.js → services/PaneAnalyzer.js} +1 -1
- package/dist/services/PaneAnalyzer.js.map +1 -0
- package/dist/services/PaneLifecycleManager.d.ts +60 -0
- package/dist/services/PaneLifecycleManager.d.ts.map +1 -0
- package/dist/services/PaneLifecycleManager.js +119 -0
- package/dist/services/PaneLifecycleManager.js.map +1 -0
- package/dist/services/PaneWorkerManager.d.ts.map +1 -1
- package/dist/services/PaneWorkerManager.js +41 -12
- package/dist/services/PaneWorkerManager.js.map +1 -1
- package/dist/services/PopupManager.d.ts +68 -0
- package/dist/services/PopupManager.d.ts.map +1 -0
- package/dist/services/PopupManager.js +415 -0
- package/dist/services/PopupManager.js.map +1 -0
- package/dist/services/StatusDetector.js +1 -1
- package/dist/services/StatusDetector.js.map +1 -1
- package/dist/services/TerminalStreamer.d.ts +1 -0
- package/dist/services/TerminalStreamer.d.ts.map +1 -1
- package/dist/services/TerminalStreamer.js +22 -16
- package/dist/services/TerminalStreamer.js.map +1 -1
- package/dist/services/TmuxService.d.ts +298 -0
- package/dist/services/TmuxService.d.ts.map +1 -0
- package/dist/services/TmuxService.js +768 -0
- package/dist/services/TmuxService.js.map +1 -0
- package/dist/services/TunnelService.d.ts +1 -0
- package/dist/services/TunnelService.d.ts.map +1 -1
- package/dist/services/TunnelService.js +57 -15
- package/dist/services/TunnelService.js.map +1 -1
- package/dist/shared/StateManager.d.ts +49 -1
- package/dist/shared/StateManager.d.ts.map +1 -1
- package/dist/shared/StateManager.js +97 -2
- package/dist/shared/StateManager.js.map +1 -1
- package/dist/theme/colors.d.ts +25 -0
- package/dist/theme/colors.d.ts.map +1 -0
- package/dist/theme/colors.js +33 -0
- package/dist/theme/colors.js.map +1 -0
- package/dist/types.d.ts +18 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/asciiArt.d.ts +26 -0
- package/dist/utils/asciiArt.d.ts.map +1 -0
- package/dist/utils/asciiArt.js +75 -0
- package/dist/utils/asciiArt.js.map +1 -0
- package/dist/utils/conflictMonitor.d.ts +20 -0
- package/dist/utils/conflictMonitor.d.ts.map +1 -0
- package/dist/utils/conflictMonitor.js +113 -0
- package/dist/utils/conflictMonitor.js.map +1 -0
- package/dist/utils/conflictResolutionPane.d.ts.map +1 -1
- package/dist/utils/conflictResolutionPane.js +75 -80
- package/dist/utils/conflictResolutionPane.js.map +1 -1
- package/dist/utils/errorHandling.d.ts +37 -0
- package/dist/utils/errorHandling.d.ts.map +1 -0
- package/dist/utils/errorHandling.js +112 -0
- package/dist/utils/errorHandling.js.map +1 -0
- package/dist/utils/fileScanner.d.ts +23 -0
- package/dist/utils/fileScanner.d.ts.map +1 -0
- package/dist/utils/fileScanner.js +123 -0
- package/dist/utils/fileScanner.js.map +1 -0
- package/dist/utils/generated-agents-doc.d.ts +1 -1
- package/dist/utils/generated-agents-doc.js +1 -1
- package/dist/utils/git.d.ts +4 -0
- package/dist/utils/git.d.ts.map +1 -1
- package/dist/utils/git.js +15 -0
- package/dist/utils/git.js.map +1 -1
- package/dist/utils/hooks.d.ts.map +1 -1
- package/dist/utils/hooks.js +65 -36
- package/dist/utils/hooks.js.map +1 -1
- package/dist/utils/hooksDocs.d.ts +1 -1
- package/dist/utils/layoutManager.d.ts +49 -0
- package/dist/utils/layoutManager.d.ts.map +1 -0
- package/dist/utils/layoutManager.js +249 -0
- package/dist/utils/layoutManager.js.map +1 -0
- package/dist/utils/mergeExecution.d.ts.map +1 -1
- package/dist/utils/mergeExecution.js +8 -1
- package/dist/utils/mergeExecution.js.map +1 -1
- package/dist/utils/mergeValidation.d.ts.map +1 -1
- package/dist/utils/mergeValidation.js +42 -13
- package/dist/utils/mergeValidation.js.map +1 -1
- package/dist/utils/paneCreation.d.ts.map +1 -1
- package/dist/utils/paneCreation.js +210 -88
- package/dist/utils/paneCreation.js.map +1 -1
- package/dist/utils/paneRebinding.d.ts +14 -0
- package/dist/utils/paneRebinding.d.ts.map +1 -0
- package/dist/utils/paneRebinding.js +28 -0
- package/dist/utils/paneRebinding.js.map +1 -0
- package/dist/utils/popup.d.ts +97 -0
- package/dist/utils/popup.d.ts.map +1 -0
- package/dist/utils/popup.js +503 -0
- package/dist/utils/popup.js.map +1 -0
- package/dist/utils/postPaneCleanup.d.ts +12 -0
- package/dist/utils/postPaneCleanup.d.ts.map +1 -0
- package/dist/utils/postPaneCleanup.js +54 -0
- package/dist/utils/postPaneCleanup.js.map +1 -0
- package/dist/utils/shellPaneDetection.d.ts +44 -0
- package/dist/utils/shellPaneDetection.d.ts.map +1 -0
- package/dist/utils/shellPaneDetection.js +179 -0
- package/dist/utils/shellPaneDetection.js.map +1 -0
- package/dist/utils/systemCheck.d.ts +19 -0
- package/dist/utils/systemCheck.d.ts.map +1 -0
- package/dist/utils/systemCheck.js +160 -0
- package/dist/utils/systemCheck.js.map +1 -0
- package/dist/utils/tmux.d.ts +72 -1
- package/dist/utils/tmux.d.ts.map +1 -1
- package/dist/utils/tmux.js +369 -99
- package/dist/utils/tmux.js.map +1 -1
- package/dist/utils/welcomePane.d.ts +22 -0
- package/dist/utils/welcomePane.d.ts.map +1 -0
- package/dist/utils/welcomePane.js +111 -0
- package/dist/utils/welcomePane.js.map +1 -0
- package/dist/utils/welcomePaneManager.d.ts +36 -0
- package/dist/utils/welcomePaneManager.d.ts.map +1 -0
- package/dist/utils/welcomePaneManager.js +160 -0
- package/dist/utils/welcomePaneManager.js.map +1 -0
- package/dist/workers/PaneWorker.js +8 -8
- package/dist/workers/PaneWorker.js.map +1 -1
- package/dist/workers/updateChecker.js +1 -1
- package/dist/workers/updateChecker.js.map +1 -1
- package/package.json +7 -2
- package/dist/AutoUpdater.d.ts.map +0 -1
- package/dist/AutoUpdater.js.map +0 -1
- package/dist/BetterTextInput.d.ts +0 -10
- package/dist/BetterTextInput.d.ts.map +0 -1
- package/dist/BetterTextInput.js +0 -177
- package/dist/BetterTextInput.js.map +0 -1
- package/dist/CleanTextInput.d.ts +0 -10
- package/dist/CleanTextInput.d.ts.map +0 -1
- package/dist/CleanTextInput.js.map +0 -1
- package/dist/EnhancedTextInput.d.ts +0 -13
- package/dist/EnhancedTextInput.d.ts.map +0 -1
- package/dist/EnhancedTextInput.js +0 -443
- package/dist/EnhancedTextInput.js.map +0 -1
- package/dist/GeminiTextInput.d.ts +0 -12
- package/dist/GeminiTextInput.d.ts.map +0 -1
- package/dist/GeminiTextInput.js +0 -210
- package/dist/GeminiTextInput.js.map +0 -1
- package/dist/MergePane.d.ts.map +0 -1
- package/dist/MergePane.js.map +0 -1
- package/dist/MultilineTextInput.d.ts +0 -10
- package/dist/MultilineTextInput.d.ts.map +0 -1
- package/dist/MultilineTextInput.js +0 -184
- package/dist/MultilineTextInput.js.map +0 -1
- package/dist/PaneAnalyzer.d.ts.map +0 -1
- package/dist/PaneAnalyzer.js.map +0 -1
- package/dist/SimpleEnhancedInput.d.ts +0 -13
- package/dist/SimpleEnhancedInput.d.ts.map +0 -1
- package/dist/SimpleEnhancedInput.js +0 -639
- package/dist/SimpleEnhancedInput.js.map +0 -1
- package/dist/SimpleGeminiInput.d.ts +0 -12
- package/dist/SimpleGeminiInput.d.ts.map +0 -1
- package/dist/SimpleGeminiInput.js +0 -223
- package/dist/SimpleGeminiInput.js.map +0 -1
- package/dist/StyledTextInput.d.ts.map +0 -1
- package/dist/StyledTextInput.js.map +0 -1
- package/dist/components/ActionChoiceDialog.d.ts.map +0 -1
- package/dist/components/ActionChoiceDialog.js.map +0 -1
- package/dist/components/ActionConfirmDialog.d.ts.map +0 -1
- package/dist/components/ActionConfirmDialog.js.map +0 -1
- package/dist/components/ActionInputDialog.d.ts.map +0 -1
- package/dist/components/ActionInputDialog.js.map +0 -1
- package/dist/components/ActionProgressDialog.d.ts.map +0 -1
- package/dist/components/ActionProgressDialog.js.map +0 -1
- package/dist/components/AgentChoiceDialog.d.ts.map +0 -1
- package/dist/components/AgentChoiceDialog.js.map +0 -1
- package/dist/components/CloseOptionsDialog.d.ts.map +0 -1
- package/dist/components/CloseOptionsDialog.js.map +0 -1
- package/dist/components/CommandPromptDialog.d.ts.map +0 -1
- package/dist/components/CommandPromptDialog.js.map +0 -1
- package/dist/components/CreatingIndicator.d.ts.map +0 -1
- package/dist/components/CreatingIndicator.js.map +0 -1
- package/dist/components/FileCopyPrompt.d.ts.map +0 -1
- package/dist/components/FileCopyPrompt.js.map +0 -1
- package/dist/components/FooterHelp.d.ts +0 -10
- package/dist/components/FooterHelp.d.ts.map +0 -1
- package/dist/components/FooterHelp.js +0 -19
- package/dist/components/FooterHelp.js.map +0 -1
- package/dist/components/HooksDialog.d.ts.map +0 -1
- package/dist/components/HooksDialog.js.map +0 -1
- package/dist/components/KebabMenu.d.ts.map +0 -1
- package/dist/components/KebabMenu.js.map +0 -1
- package/dist/components/LoadingIndicator.d.ts.map +0 -1
- package/dist/components/LoadingIndicator.js.map +0 -1
- package/dist/components/MergeConfirmationDialog.d.ts.map +0 -1
- package/dist/components/MergeConfirmationDialog.js.map +0 -1
- package/dist/components/NewPaneDialog.d.ts +0 -9
- package/dist/components/NewPaneDialog.d.ts.map +0 -1
- package/dist/components/NewPaneDialog.js +0 -11
- package/dist/components/NewPaneDialog.js.map +0 -1
- package/dist/components/PaneCard.d.ts.map +0 -1
- package/dist/components/PaneCard.js +0 -38
- package/dist/components/PaneCard.js.map +0 -1
- package/dist/components/PanesGrid.d.ts +0 -14
- package/dist/components/PanesGrid.d.ts.map +0 -1
- package/dist/components/PanesGrid.js +0 -19
- package/dist/components/PanesGrid.js.map +0 -1
- package/dist/components/QRCode.d.ts.map +0 -1
- package/dist/components/QRCode.js.map +0 -1
- package/dist/components/RunningIndicator.d.ts.map +0 -1
- package/dist/components/RunningIndicator.js.map +0 -1
- package/dist/components/SettingsDialog.d.ts.map +0 -1
- package/dist/components/SettingsDialog.js.map +0 -1
- package/dist/components/Spinner.d.ts.map +0 -1
- package/dist/components/Spinner.js.map +0 -1
- package/dist/components/UpdateDialog.d.ts.map +0 -1
- package/dist/components/UpdateDialog.js.map +0 -1
- package/dist/components/UpdatingIndicator.d.ts.map +0 -1
- package/dist/components/UpdatingIndicator.js.map +0 -1
- package/dist/server/static.d.ts +0 -6
- package/dist/server/static.d.ts.map +0 -1
- package/dist/server/static.js +0 -3040
- package/dist/server/static.js.map +0 -1
- /package/dist/components/{ActionChoiceDialog.js → dialogs/ActionChoiceDialog.js} +0 -0
- /package/dist/components/{ActionConfirmDialog.d.ts → dialogs/ActionConfirmDialog.d.ts} +0 -0
- /package/dist/components/{ActionConfirmDialog.js → dialogs/ActionConfirmDialog.js} +0 -0
- /package/dist/components/{ActionInputDialog.d.ts → dialogs/ActionInputDialog.d.ts} +0 -0
- /package/dist/components/{ActionProgressDialog.d.ts → dialogs/ActionProgressDialog.d.ts} +0 -0
- /package/dist/components/{ActionProgressDialog.js → dialogs/ActionProgressDialog.js} +0 -0
- /package/dist/components/{AgentChoiceDialog.d.ts → dialogs/AgentChoiceDialog.d.ts} +0 -0
- /package/dist/components/{AgentChoiceDialog.js → dialogs/AgentChoiceDialog.js} +0 -0
- /package/dist/components/{CloseOptionsDialog.js → dialogs/CloseOptionsDialog.js} +0 -0
- /package/dist/components/{CommandPromptDialog.d.ts → dialogs/CommandPromptDialog.d.ts} +0 -0
- /package/dist/components/{HooksDialog.d.ts → dialogs/HooksDialog.d.ts} +0 -0
- /package/dist/components/{HooksDialog.js → dialogs/HooksDialog.js} +0 -0
- /package/dist/components/{MergeConfirmationDialog.js → dialogs/MergeConfirmationDialog.js} +0 -0
- /package/dist/components/{SettingsDialog.js → dialogs/SettingsDialog.js} +0 -0
- /package/dist/components/{UpdateDialog.d.ts → dialogs/UpdateDialog.d.ts} +0 -0
- /package/dist/components/{UpdateDialog.js → dialogs/UpdateDialog.js} +0 -0
- /package/dist/components/{CreatingIndicator.d.ts → indicators/CreatingIndicator.d.ts} +0 -0
- /package/dist/components/{CreatingIndicator.js → indicators/CreatingIndicator.js} +0 -0
- /package/dist/components/{LoadingIndicator.d.ts → indicators/LoadingIndicator.d.ts} +0 -0
- /package/dist/components/{LoadingIndicator.js → indicators/LoadingIndicator.js} +0 -0
- /package/dist/components/{RunningIndicator.d.ts → indicators/RunningIndicator.d.ts} +0 -0
- /package/dist/components/{RunningIndicator.js → indicators/RunningIndicator.js} +0 -0
- /package/dist/components/{Spinner.d.ts → indicators/Spinner.d.ts} +0 -0
- /package/dist/components/{Spinner.js → indicators/Spinner.js} +0 -0
- /package/dist/components/{UpdatingIndicator.d.ts → indicators/UpdatingIndicator.d.ts} +0 -0
- /package/dist/components/{UpdatingIndicator.js → indicators/UpdatingIndicator.js} +0 -0
- /package/dist/{StyledTextInput.d.ts → components/inputs/StyledTextInput.d.ts} +0 -0
- /package/dist/{StyledTextInput.js → components/inputs/StyledTextInput.js} +0 -0
- /package/dist/components/{KebabMenu.js → panes/KebabMenu.js} +0 -0
- /package/dist/{MergePane.d.ts → components/panes/MergePane.d.ts} +0 -0
- /package/dist/components/{FileCopyPrompt.d.ts → ui/FileCopyPrompt.d.ts} +0 -0
- /package/dist/components/{FileCopyPrompt.js → ui/FileCopyPrompt.js} +0 -0
- /package/dist/components/{QRCode.d.ts → ui/QRCode.d.ts} +0 -0
- /package/dist/components/{QRCode.js → ui/QRCode.js} +0 -0
- /package/dist/{PaneAnalyzer.d.ts → services/PaneAnalyzer.d.ts} +0 -0
package/dist/DmuxApp.js
CHANGED
|
@@ -1,123 +1,112 @@
|
|
|
1
|
-
import React, { useState, useEffect } from
|
|
2
|
-
import { Box, Text,
|
|
3
|
-
import {
|
|
4
|
-
import
|
|
5
|
-
import { createRequire } from 'module';
|
|
1
|
+
import React, { useState, useEffect } from "react";
|
|
2
|
+
import { Box, Text, useApp, useStdout } from "ink";
|
|
3
|
+
import { createRequire } from "module";
|
|
4
|
+
import { TmuxService } from "./services/TmuxService.js";
|
|
6
5
|
// Hooks
|
|
7
|
-
import usePanes from
|
|
8
|
-
import useProjectSettings from
|
|
9
|
-
import useTerminalWidth from
|
|
10
|
-
import useNavigation from
|
|
11
|
-
import useAutoUpdater from
|
|
12
|
-
import useAgentDetection from
|
|
13
|
-
import useAgentStatus from
|
|
14
|
-
import usePaneRunner from
|
|
15
|
-
import usePaneCreation from
|
|
16
|
-
import useActionSystem from
|
|
6
|
+
import usePanes from "./hooks/usePanes.js";
|
|
7
|
+
import useProjectSettings from "./hooks/useProjectSettings.js";
|
|
8
|
+
import useTerminalWidth from "./hooks/useTerminalWidth.js";
|
|
9
|
+
import useNavigation from "./hooks/useNavigation.js";
|
|
10
|
+
import useAutoUpdater from "./hooks/useAutoUpdater.js";
|
|
11
|
+
import useAgentDetection from "./hooks/useAgentDetection.js";
|
|
12
|
+
import useAgentStatus from "./hooks/useAgentStatus.js";
|
|
13
|
+
import usePaneRunner from "./hooks/usePaneRunner.js";
|
|
14
|
+
import usePaneCreation from "./hooks/usePaneCreation.js";
|
|
15
|
+
import useActionSystem from "./hooks/useActionSystem.js";
|
|
16
|
+
import { useStatusMessages } from "./hooks/useStatusMessages.js";
|
|
17
|
+
import { useLayoutManagement } from "./hooks/useLayoutManagement.js";
|
|
18
|
+
import { useInputHandling } from "./hooks/useInputHandling.js";
|
|
19
|
+
import { useDialogState } from "./hooks/useDialogState.js";
|
|
20
|
+
import { useTunnelManagement } from "./hooks/useTunnelManagement.js";
|
|
21
|
+
import { useDebugInfo } from "./hooks/useDebugInfo.js";
|
|
17
22
|
// Utils
|
|
18
|
-
import {
|
|
19
|
-
import {
|
|
20
|
-
import {
|
|
21
|
-
import {
|
|
22
|
-
import {
|
|
23
|
-
import {
|
|
24
|
-
import {
|
|
25
|
-
import {
|
|
26
|
-
import {
|
|
23
|
+
import { SIDEBAR_WIDTH } from "./utils/layoutManager.js";
|
|
24
|
+
import { supportsPopups } from "./utils/popup.js";
|
|
25
|
+
import { StateManager } from "./shared/StateManager.js";
|
|
26
|
+
import { REPAINT_SPINNER_DURATION, } from "./constants/timing.js";
|
|
27
|
+
import { getStatusDetector, } from "./services/StatusDetector.js";
|
|
28
|
+
import { SettingsManager } from "./utils/settingsManager.js";
|
|
29
|
+
import { useServices } from "./hooks/useServices.js";
|
|
30
|
+
import { PaneLifecycleManager } from "./services/PaneLifecycleManager.js";
|
|
31
|
+
import { fileURLToPath } from "url";
|
|
32
|
+
import { dirname } from "path";
|
|
33
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
34
|
+
const __dirname = dirname(__filename);
|
|
27
35
|
const require = createRequire(import.meta.url);
|
|
28
|
-
const packageJson = require(
|
|
29
|
-
import PanesGrid from
|
|
30
|
-
import
|
|
31
|
-
import
|
|
32
|
-
import
|
|
33
|
-
import
|
|
34
|
-
import
|
|
35
|
-
import
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
import QRCode from './components/QRCode.js';
|
|
40
|
-
import KebabMenu from './components/KebabMenu.js';
|
|
41
|
-
import ActionChoiceDialog from './components/ActionChoiceDialog.js';
|
|
42
|
-
import ActionConfirmDialog from './components/ActionConfirmDialog.js';
|
|
43
|
-
import ActionInputDialog from './components/ActionInputDialog.js';
|
|
44
|
-
import ActionProgressDialog from './components/ActionProgressDialog.js';
|
|
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 }) => {
|
|
36
|
+
const packageJson = require("../package.json");
|
|
37
|
+
import PanesGrid from "./components/panes/PanesGrid.js";
|
|
38
|
+
import CommandPromptDialog from "./components/dialogs/CommandPromptDialog.js";
|
|
39
|
+
import FileCopyPrompt from "./components/ui/FileCopyPrompt.js";
|
|
40
|
+
import LoadingIndicator from "./components/indicators/LoadingIndicator.js";
|
|
41
|
+
import RunningIndicator from "./components/indicators/RunningIndicator.js";
|
|
42
|
+
import UpdatingIndicator from "./components/indicators/UpdatingIndicator.js";
|
|
43
|
+
import FooterHelp from "./components/ui/FooterHelp.js";
|
|
44
|
+
const DmuxApp = ({ panesFile, projectName, sessionName, settingsFile, projectRoot, autoUpdater, serverPort, server, controlPaneId, }) => {
|
|
45
|
+
const { stdout } = useStdout();
|
|
46
|
+
const terminalHeight = stdout?.rows || 40;
|
|
48
47
|
/* panes state moved to usePanes */
|
|
49
48
|
const [selectedIndex, setSelectedIndex] = useState(0);
|
|
50
|
-
const
|
|
51
|
-
const [newPanePrompt, setNewPanePrompt] = useState('');
|
|
52
|
-
const [statusMessage, setStatusMessage] = useState('');
|
|
49
|
+
const { statusMessage, setStatusMessage, showStatus, clearStatus } = useStatusMessages();
|
|
53
50
|
const [isCreatingPane, setIsCreatingPane] = useState(false);
|
|
54
|
-
const [showQRCode, setShowQRCode] = useState(false);
|
|
55
|
-
const [tunnelUrl, setTunnelUrl] = useState(null);
|
|
56
|
-
const [isCreatingTunnel, setIsCreatingTunnel] = useState(false);
|
|
57
51
|
// Settings state
|
|
58
52
|
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);
|
|
65
53
|
// Force repaint trigger - incrementing this causes Ink to re-render
|
|
66
54
|
const [forceRepaintTrigger, setForceRepaintTrigger] = useState(0);
|
|
67
55
|
// Spinner state - shows for a few frames to force render
|
|
68
56
|
const [showRepaintSpinner, setShowRepaintSpinner] = useState(false);
|
|
69
57
|
const { projectSettings, saveSettings } = useProjectSettings(settingsFile);
|
|
70
|
-
//
|
|
71
|
-
const
|
|
72
|
-
const
|
|
73
|
-
|
|
74
|
-
const
|
|
75
|
-
const
|
|
76
|
-
|
|
77
|
-
const
|
|
78
|
-
const [runningCommand, setRunningCommand] = useState(false);
|
|
79
|
-
const [quitConfirmMode, setQuitConfirmMode] = useState(false);
|
|
80
|
-
const [showKebabMenu, setShowKebabMenu] = useState(false);
|
|
81
|
-
const [kebabMenuPaneIndex, setKebabMenuPaneIndex] = useState(null);
|
|
82
|
-
const [kebabMenuOption, setKebabMenuOption] = useState(0);
|
|
83
|
-
const [kebabMenuActions, setKebabMenuActions] = useState([]);
|
|
84
|
-
// Debug message state - for temporary logging messages
|
|
85
|
-
const [debugMessage, setDebugMessage] = useState('');
|
|
58
|
+
// Dialog state management
|
|
59
|
+
const dialogState = useDialogState();
|
|
60
|
+
const { showCommandPrompt, setShowCommandPrompt, commandInput, setCommandInput, showFileCopyPrompt, setShowFileCopyPrompt, currentCommandType, setCurrentCommandType, runningCommand, setRunningCommand, quitConfirmMode, setQuitConfirmMode, } = dialogState;
|
|
61
|
+
// Tunnel/network state management
|
|
62
|
+
const tunnelState = useTunnelManagement();
|
|
63
|
+
const { tunnelUrl, setTunnelUrl, tunnelCreating, setTunnelCreating, tunnelCopied, setTunnelCopied, localIp, setLocalIp, } = tunnelState;
|
|
64
|
+
// Debug/development info
|
|
65
|
+
const { debugMessage, setDebugMessage, currentBranch } = useDebugInfo(__dirname);
|
|
86
66
|
// Update state handled by hook
|
|
87
|
-
const { updateInfo,
|
|
67
|
+
const { updateInfo, isUpdating, updateAvailable, } = useAutoUpdater(autoUpdater, setStatusMessage);
|
|
88
68
|
const { exit } = useApp();
|
|
69
|
+
// Flag to ignore input temporarily after popup closes (prevents buffered keys)
|
|
70
|
+
const [ignoreInput, setIgnoreInput] = useState(false);
|
|
89
71
|
// Agent selection state
|
|
90
72
|
const { availableAgents } = useAgentDetection();
|
|
91
|
-
const [showAgentChoiceDialog, setShowAgentChoiceDialog] = useState(false);
|
|
92
73
|
const [agentChoice, setAgentChoice] = useState(null);
|
|
93
|
-
|
|
74
|
+
// Popup support detection
|
|
75
|
+
const [popupsSupported, setPopupsSupported] = useState(false);
|
|
94
76
|
// Track terminal dimensions for responsive layout
|
|
95
77
|
const terminalWidth = useTerminalWidth();
|
|
78
|
+
// Track unread error and warning counts for logs badge
|
|
79
|
+
const [unreadErrorCount, setUnreadErrorCount] = useState(0);
|
|
80
|
+
const [unreadWarningCount, setUnreadWarningCount] = useState(0);
|
|
81
|
+
// Subscribe to StateManager for unread error/warning count updates
|
|
82
|
+
useEffect(() => {
|
|
83
|
+
const stateManager = StateManager.getInstance();
|
|
84
|
+
const updateCounts = () => {
|
|
85
|
+
setUnreadErrorCount(stateManager.getUnreadErrorCount());
|
|
86
|
+
setUnreadWarningCount(stateManager.getUnreadWarningCount());
|
|
87
|
+
};
|
|
88
|
+
// Initial count
|
|
89
|
+
updateCounts();
|
|
90
|
+
// Subscribe to changes
|
|
91
|
+
const unsubscribe = stateManager.subscribe(updateCounts);
|
|
92
|
+
return () => {
|
|
93
|
+
unsubscribe();
|
|
94
|
+
};
|
|
95
|
+
}, []);
|
|
96
96
|
// Panes state and persistence (skipLoading will be updated after actionSystem is initialized)
|
|
97
97
|
const { panes, setPanes, isLoading, loadPanes, savePanes } = usePanes(panesFile, false);
|
|
98
|
-
//
|
|
99
|
-
//
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
onPaneRemove: (paneId) => {
|
|
109
|
-
// Mark this pane as intentionally closed
|
|
110
|
-
intentionallyClosedPanes.current.add(paneId);
|
|
111
|
-
const updated = panes.filter(p => p.id !== paneId);
|
|
112
|
-
setPanes(updated);
|
|
113
|
-
// Clean up the tracking after a delay (in case of race conditions)
|
|
114
|
-
setTimeout(() => {
|
|
115
|
-
intentionallyClosedPanes.current.delete(paneId);
|
|
116
|
-
}, 5000);
|
|
117
|
-
},
|
|
118
|
-
});
|
|
98
|
+
// Pane lifecycle manager - handles locking to prevent race conditions
|
|
99
|
+
// Replaces the old timeout-based intentionallyClosedPanes Set
|
|
100
|
+
const lifecycleManager = React.useMemo(() => PaneLifecycleManager.getInstance(), []);
|
|
101
|
+
// Clean up stale lifecycle operations periodically
|
|
102
|
+
useEffect(() => {
|
|
103
|
+
const cleanupInterval = setInterval(() => {
|
|
104
|
+
lifecycleManager.cleanupStaleOperations();
|
|
105
|
+
}, 60000); // Every 60 seconds
|
|
106
|
+
return () => clearInterval(cleanupInterval);
|
|
107
|
+
}, [lifecycleManager]);
|
|
119
108
|
// Pane runner
|
|
120
|
-
const { copyNonGitFiles, runCommandInternal,
|
|
109
|
+
const { copyNonGitFiles, runCommandInternal, } = usePaneRunner({
|
|
121
110
|
panes,
|
|
122
111
|
savePanes,
|
|
123
112
|
projectSettings,
|
|
@@ -126,24 +115,47 @@ const DmuxApp = ({ panesFile, projectName, sessionName, settingsFile, projectRoo
|
|
|
126
115
|
});
|
|
127
116
|
// Force repaint helper - shows spinner for a few frames to force full re-render
|
|
128
117
|
const forceRepaint = () => {
|
|
129
|
-
setForceRepaintTrigger(prev => prev + 1);
|
|
118
|
+
setForceRepaintTrigger((prev) => prev + 1);
|
|
130
119
|
setShowRepaintSpinner(true);
|
|
131
120
|
// Hide spinner after a few frames (enough to trigger multiple renders)
|
|
132
|
-
setTimeout(() => setShowRepaintSpinner(false),
|
|
121
|
+
setTimeout(() => setShowRepaintSpinner(false), REPAINT_SPINNER_DURATION);
|
|
133
122
|
};
|
|
134
123
|
// Force repaint effect - ensures Ink re-renders when trigger changes
|
|
135
124
|
useEffect(() => {
|
|
136
125
|
if (forceRepaintTrigger > 0) {
|
|
137
126
|
// Small delay to ensure terminal is ready
|
|
138
|
-
const timer = setTimeout(() => {
|
|
127
|
+
const timer = setTimeout(async () => {
|
|
139
128
|
try {
|
|
140
|
-
|
|
129
|
+
const tmuxService = TmuxService.getInstance();
|
|
130
|
+
await tmuxService.refreshClient();
|
|
141
131
|
}
|
|
142
132
|
catch { }
|
|
143
133
|
}, 50);
|
|
144
134
|
return () => clearTimeout(timer);
|
|
145
135
|
}
|
|
146
136
|
}, [forceRepaintTrigger]);
|
|
137
|
+
// Get local network IP on mount
|
|
138
|
+
useEffect(() => {
|
|
139
|
+
const getLocalIp = async () => {
|
|
140
|
+
try {
|
|
141
|
+
// Get local IP address (not 127.0.0.1)
|
|
142
|
+
const { execSync } = await import("child_process");
|
|
143
|
+
const result = execSync(`hostname -I 2>/dev/null || ifconfig | grep "inet " | grep -v 127.0.0.1 | awk '{print $2}' | head -1`, {
|
|
144
|
+
encoding: "utf-8",
|
|
145
|
+
stdio: "pipe",
|
|
146
|
+
}).trim();
|
|
147
|
+
if (result) {
|
|
148
|
+
setLocalIp(result.split(" ")[0]); // Take first IP if multiple
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
catch {
|
|
152
|
+
// Fallback to 127.0.0.1
|
|
153
|
+
setLocalIp("127.0.0.1");
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
getLocalIp();
|
|
157
|
+
}, []);
|
|
158
|
+
// Spinner animation and branch detection now handled in hooks
|
|
147
159
|
// Pane creation
|
|
148
160
|
const { createNewPane: createNewPaneHook } = usePaneCreation({
|
|
149
161
|
panes,
|
|
@@ -151,18 +163,37 @@ const DmuxApp = ({ panesFile, projectName, sessionName, settingsFile, projectRoo
|
|
|
151
163
|
projectName,
|
|
152
164
|
setIsCreatingPane,
|
|
153
165
|
setStatusMessage,
|
|
154
|
-
setNewPanePrompt,
|
|
155
166
|
loadPanes,
|
|
156
167
|
panesFile,
|
|
157
168
|
availableAgents,
|
|
158
169
|
forceRepaint,
|
|
159
170
|
});
|
|
171
|
+
// Initialize services
|
|
172
|
+
const { popupManager } = useServices({
|
|
173
|
+
// PopupManager config
|
|
174
|
+
sidebarWidth: SIDEBAR_WIDTH,
|
|
175
|
+
projectRoot: projectRoot || process.cwd(),
|
|
176
|
+
popupsSupported,
|
|
177
|
+
terminalWidth,
|
|
178
|
+
terminalHeight,
|
|
179
|
+
availableAgents,
|
|
180
|
+
agentChoice,
|
|
181
|
+
serverPort,
|
|
182
|
+
server,
|
|
183
|
+
settingsManager,
|
|
184
|
+
projectSettings,
|
|
185
|
+
// Callbacks
|
|
186
|
+
setStatusMessage,
|
|
187
|
+
setIgnoreInput,
|
|
188
|
+
savePanes,
|
|
189
|
+
loadPanes,
|
|
190
|
+
});
|
|
160
191
|
// Listen for status updates with analysis data and merge into panes
|
|
161
192
|
useEffect(() => {
|
|
162
193
|
const statusDetector = getStatusDetector();
|
|
163
194
|
const handleStatusUpdate = (event) => {
|
|
164
|
-
setPanes(prevPanes => {
|
|
165
|
-
const updatedPanes = prevPanes.map(pane => {
|
|
195
|
+
setPanes((prevPanes) => {
|
|
196
|
+
const updatedPanes = prevPanes.map((pane) => {
|
|
166
197
|
if (pane.id === event.paneId) {
|
|
167
198
|
const updated = {
|
|
168
199
|
...pane,
|
|
@@ -186,22 +217,23 @@ const DmuxApp = ({ panesFile, projectName, sessionName, settingsFile, projectRoo
|
|
|
186
217
|
updated.analyzerError = event.analyzerError;
|
|
187
218
|
}
|
|
188
219
|
// Clear option dialog data when transitioning away from 'waiting' state
|
|
189
|
-
if (event.status !==
|
|
220
|
+
if (event.status !== "waiting" && pane.agentStatus === "waiting") {
|
|
190
221
|
updated.optionsQuestion = undefined;
|
|
191
222
|
updated.options = undefined;
|
|
192
223
|
updated.potentialHarm = undefined;
|
|
193
224
|
}
|
|
194
225
|
// Clear summary when transitioning away from 'idle' state
|
|
195
|
-
if (event.status !==
|
|
226
|
+
if (event.status !== "idle" && pane.agentStatus === "idle") {
|
|
196
227
|
updated.agentSummary = undefined;
|
|
197
228
|
}
|
|
198
229
|
// Clear analyzer error when successfully getting a new analysis
|
|
199
230
|
// or when transitioning to 'working' status
|
|
200
|
-
if (event.status ===
|
|
231
|
+
if (event.status === "working") {
|
|
201
232
|
updated.analyzerError = undefined;
|
|
202
233
|
}
|
|
203
|
-
else if (event.status ===
|
|
204
|
-
if (event.analyzerError === undefined &&
|
|
234
|
+
else if (event.status === "waiting" || event.status === "idle") {
|
|
235
|
+
if (event.analyzerError === undefined &&
|
|
236
|
+
(event.optionsQuestion || event.summary)) {
|
|
205
237
|
updated.analyzerError = undefined;
|
|
206
238
|
}
|
|
207
239
|
}
|
|
@@ -210,15 +242,15 @@ const DmuxApp = ({ panesFile, projectName, sessionName, settingsFile, projectRoo
|
|
|
210
242
|
return pane;
|
|
211
243
|
});
|
|
212
244
|
// Persist to disk - ConfigWatcher will handle syncing to StateManager
|
|
213
|
-
savePanes(updatedPanes).catch(err => {
|
|
214
|
-
console.error(
|
|
245
|
+
savePanes(updatedPanes).catch((err) => {
|
|
246
|
+
console.error("Failed to save panes after status update:", err);
|
|
215
247
|
});
|
|
216
248
|
return updatedPanes;
|
|
217
249
|
});
|
|
218
250
|
};
|
|
219
|
-
statusDetector.on(
|
|
251
|
+
statusDetector.on("status-updated", handleStatusUpdate);
|
|
220
252
|
return () => {
|
|
221
|
-
statusDetector.off(
|
|
253
|
+
statusDetector.off("status-updated", handleStatusUpdate);
|
|
222
254
|
};
|
|
223
255
|
}, [setPanes, savePanes]);
|
|
224
256
|
// Note: No need to sync panes with StateManager here.
|
|
@@ -243,62 +275,29 @@ const DmuxApp = ({ panesFile, projectName, sessionName, settingsFile, projectRoo
|
|
|
243
275
|
const handleTermination = () => {
|
|
244
276
|
cleanExit();
|
|
245
277
|
};
|
|
246
|
-
process.on(
|
|
247
|
-
//
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
278
|
+
process.on("SIGTERM", handleTermination);
|
|
279
|
+
// Check if tmux supports popups (3.2+) and enable mouse mode for click-outside-to-close
|
|
280
|
+
const popupSupport = supportsPopups();
|
|
281
|
+
setPopupsSupported(popupSupport);
|
|
282
|
+
if (popupSupport) {
|
|
283
|
+
// Enable mouse mode only for this dmux session (not global)
|
|
284
|
+
}
|
|
252
285
|
return () => {
|
|
253
|
-
process.removeListener(
|
|
286
|
+
process.removeListener("SIGTERM", handleTermination);
|
|
254
287
|
};
|
|
255
288
|
}, []);
|
|
256
|
-
// Auto-show new pane dialog when starting with no panes
|
|
257
|
-
useEffect(() => {
|
|
258
|
-
// Only show the dialog if:
|
|
259
|
-
// 1. Initial load is complete (!isLoading)
|
|
260
|
-
// 2. We have no panes
|
|
261
|
-
// 3. We're not already showing the dialog
|
|
262
|
-
// 4. We're not showing any other dialogs or prompts
|
|
263
|
-
if (!isLoading &&
|
|
264
|
-
panes.length === 0 &&
|
|
265
|
-
!showNewPaneDialog &&
|
|
266
|
-
!actionSystem.actionState.showConfirmDialog &&
|
|
267
|
-
!actionSystem.actionState.showChoiceDialog &&
|
|
268
|
-
!actionSystem.actionState.showInputDialog &&
|
|
269
|
-
!actionSystem.actionState.showProgressDialog &&
|
|
270
|
-
!showCommandPrompt &&
|
|
271
|
-
!showFileCopyPrompt &&
|
|
272
|
-
!showAgentChoiceDialog &&
|
|
273
|
-
!isCreatingPane &&
|
|
274
|
-
!runningCommand &&
|
|
275
|
-
!isUpdating) {
|
|
276
|
-
setShowNewPaneDialog(true);
|
|
277
|
-
}
|
|
278
|
-
}, [isLoading, panes.length, showNewPaneDialog, actionSystem.actionState.showConfirmDialog, actionSystem.actionState.showChoiceDialog, actionSystem.actionState.showInputDialog, actionSystem.actionState.showProgressDialog, showCommandPrompt, showFileCopyPrompt, showAgentChoiceDialog, isCreatingPane, runningCommand, isUpdating]);
|
|
279
289
|
// Update checking moved to useAutoUpdater
|
|
280
290
|
// Set default agent choice when detection completes
|
|
281
291
|
useEffect(() => {
|
|
282
292
|
if (agentChoice == null && availableAgents.length > 0) {
|
|
283
|
-
setAgentChoice(availableAgents[0] ||
|
|
293
|
+
setAgentChoice(availableAgents[0] || "claude");
|
|
284
294
|
}
|
|
285
295
|
}, [availableAgents]);
|
|
286
|
-
//
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
// Check if this pane was intentionally closed
|
|
292
|
-
// If so, don't re-save - the close action already handled it
|
|
293
|
-
if (intentionallyClosedPanes.current.has(paneId)) {
|
|
294
|
-
return;
|
|
295
|
-
}
|
|
296
|
-
// Pane was removed unexpectedly (e.g., user killed tmux pane manually)
|
|
297
|
-
// Remove it from our tracking
|
|
298
|
-
const updatedPanes = panes.filter(p => p.id !== paneId);
|
|
299
|
-
savePanes(updatedPanes);
|
|
300
|
-
},
|
|
301
|
-
});
|
|
296
|
+
// Welcome pane is now fully event-based:
|
|
297
|
+
// - Created at startup (in src/index.ts)
|
|
298
|
+
// - Destroyed when first pane is created (in paneCreation.ts)
|
|
299
|
+
// - Recreated when last pane is closed (in paneActions.ts)
|
|
300
|
+
// No polling needed!
|
|
302
301
|
// loadPanes moved to usePanes
|
|
303
302
|
// getPanePositions moved to utils/tmux
|
|
304
303
|
// Navigation logic moved to hook
|
|
@@ -306,1016 +305,290 @@ const DmuxApp = ({ panesFile, projectName, sessionName, settingsFile, projectRoo
|
|
|
306
305
|
// findCardInDirection provided by useNavigation
|
|
307
306
|
// savePanes moved to usePanes
|
|
308
307
|
// applySmartLayout moved to utils/tmux
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
// Get git root directory for consistent worktree placement
|
|
315
|
-
let projectRoot;
|
|
316
|
-
try {
|
|
317
|
-
projectRoot = execSync('git rev-parse --show-toplevel', {
|
|
318
|
-
encoding: 'utf-8',
|
|
319
|
-
stdio: 'pipe'
|
|
320
|
-
}).trim();
|
|
321
|
-
}
|
|
322
|
-
catch {
|
|
323
|
-
// Fallback to current directory if not in a git repo
|
|
324
|
-
projectRoot = process.cwd();
|
|
325
|
-
}
|
|
326
|
-
// Create worktree path inside .dmux/worktrees directory
|
|
327
|
-
const worktreePath = path.join(projectRoot, '.dmux', 'worktrees', slug);
|
|
328
|
-
// Get the original pane ID (where dmux is running) before clearing
|
|
329
|
-
const originalPaneId = execSync('tmux display-message -p "#{pane_id}"', { encoding: 'utf-8' }).trim();
|
|
330
|
-
// Multiple clearing strategies to prevent artifacts
|
|
331
|
-
// 1. Clear screen with ANSI codes
|
|
332
|
-
process.stdout.write('\x1b[2J\x1b[H');
|
|
333
|
-
// 2. Fill with blank lines to push content off screen
|
|
334
|
-
process.stdout.write('\n'.repeat(100));
|
|
335
|
-
// 3. Clear tmux history and send clear command
|
|
336
|
-
try {
|
|
337
|
-
execSync('tmux clear-history', { stdio: 'pipe' });
|
|
338
|
-
execSync('tmux send-keys C-l', { stdio: 'pipe' });
|
|
308
|
+
// Helper function to handle agent choice and pane creation
|
|
309
|
+
const handlePaneCreationWithAgent = async (prompt) => {
|
|
310
|
+
const agents = availableAgents;
|
|
311
|
+
if (agents.length === 0) {
|
|
312
|
+
await createNewPaneHook(prompt);
|
|
339
313
|
}
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
await new Promise(resolve => setTimeout(resolve, 100));
|
|
343
|
-
// 4. Force tmux to refresh the display
|
|
344
|
-
try {
|
|
345
|
-
execSync('tmux refresh-client', { stdio: 'pipe' });
|
|
314
|
+
else if (agents.length === 1) {
|
|
315
|
+
await createNewPaneHook(prompt, agents[0]);
|
|
346
316
|
}
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
execSync(`tmux set-option -g pane-border-status top`, { stdio: 'pipe' });
|
|
353
|
-
}
|
|
354
|
-
catch {
|
|
355
|
-
// Ignore if already set or fails
|
|
356
|
-
}
|
|
357
|
-
// Create new pane
|
|
358
|
-
const paneInfo = execSync(`tmux split-window -h -P -F '#{pane_id}'`, { encoding: 'utf-8' }).trim();
|
|
359
|
-
// Wait for pane creation to settle
|
|
360
|
-
await new Promise(resolve => setTimeout(resolve, 500));
|
|
361
|
-
// Set pane title to match the slug
|
|
362
|
-
try {
|
|
363
|
-
execSync(`tmux select-pane -t '${paneInfo}' -T "${slug}"`, { stdio: 'pipe' });
|
|
364
|
-
}
|
|
365
|
-
catch {
|
|
366
|
-
// Ignore if setting title fails
|
|
367
|
-
}
|
|
368
|
-
// Apply smart layout based on pane count
|
|
369
|
-
const newPaneCount = paneCount + 1;
|
|
370
|
-
applySmartLayout(newPaneCount);
|
|
371
|
-
// Create git worktree and cd into it
|
|
372
|
-
// This MUST happen before launching Claude to ensure we're in the right directory
|
|
373
|
-
try {
|
|
374
|
-
// First, create the worktree and cd into it as a single command
|
|
375
|
-
// Use ; instead of && to ensure cd runs even if worktree already exists
|
|
376
|
-
const worktreeCmd = `git worktree add "${worktreePath}" -b ${slug} 2>/dev/null ; cd "${worktreePath}"`;
|
|
377
|
-
execSync(`tmux send-keys -t '${paneInfo}' '${worktreeCmd}' Enter`, { stdio: 'pipe' });
|
|
378
|
-
// Wait longer for worktree creation and cd to complete
|
|
379
|
-
// This is critical - if we don't wait long enough, Claude will start in the wrong directory
|
|
380
|
-
await new Promise(resolve => setTimeout(resolve, 2500));
|
|
381
|
-
// Verify we're in the worktree directory by sending pwd command
|
|
382
|
-
execSync(`tmux send-keys -t '${paneInfo}' 'echo "Worktree created at:" && pwd' Enter`, { stdio: 'pipe' });
|
|
383
|
-
await new Promise(resolve => setTimeout(resolve, 500));
|
|
384
|
-
setStatusMessage(agent ? `Worktree created, launching ${agent === 'opencode' ? 'opencode' : 'Claude'}...` : 'Worktree created.');
|
|
385
|
-
}
|
|
386
|
-
catch (error) {
|
|
387
|
-
// Log error but continue - worktree creation is essential
|
|
388
|
-
setStatusMessage(`Warning: Worktree issue: ${error}`);
|
|
389
|
-
// Even if worktree creation failed, try to cd to the directory in case it exists
|
|
390
|
-
execSync(`tmux send-keys -t '${paneInfo}' 'cd "${worktreePath}" 2>/dev/null || (echo "ERROR: Failed to create/enter worktree ${slug}" && pwd)' Enter`, { stdio: 'pipe' });
|
|
391
|
-
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
392
|
-
}
|
|
393
|
-
// Prepare and send the agent command
|
|
394
|
-
let escapedCmd = '';
|
|
395
|
-
if (agent === 'claude') {
|
|
396
|
-
// Claude should always be launched AFTER we're in the worktree directory
|
|
397
|
-
let claudeCmd;
|
|
398
|
-
if (prompt && prompt.trim()) {
|
|
399
|
-
const escapedPrompt = prompt
|
|
400
|
-
.replace(/\\/g, '\\\\')
|
|
401
|
-
.replace(/"/g, '\\"')
|
|
402
|
-
.replace(/`/g, '\\`')
|
|
403
|
-
.replace(/\$/g, '\\$');
|
|
404
|
-
claudeCmd = `claude "${escapedPrompt}" --permission-mode=acceptEdits`;
|
|
317
|
+
else {
|
|
318
|
+
// Multiple agents available - check for default agent setting first
|
|
319
|
+
const settings = settingsManager.getSettings();
|
|
320
|
+
if (settings.defaultAgent && agents.includes(settings.defaultAgent)) {
|
|
321
|
+
await createNewPaneHook(prompt, settings.defaultAgent);
|
|
405
322
|
}
|
|
406
323
|
else {
|
|
407
|
-
|
|
324
|
+
// Show agent choice popup
|
|
325
|
+
const selectedAgent = await popupManager.launchAgentChoicePopup();
|
|
326
|
+
if (selectedAgent) {
|
|
327
|
+
await createNewPaneHook(prompt, selectedAgent);
|
|
328
|
+
}
|
|
408
329
|
}
|
|
409
|
-
// Send Claude command to new pane
|
|
410
|
-
escapedCmd = claudeCmd.replace(/'/g, "'\\''");
|
|
411
|
-
execSync(`tmux send-keys -t '${paneInfo}' '${escapedCmd}'`, { stdio: 'pipe' });
|
|
412
|
-
execSync(`tmux send-keys -t '${paneInfo}' Enter`, { stdio: 'pipe' });
|
|
413
330
|
}
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
331
|
+
};
|
|
332
|
+
// Helper function to handle action results recursively
|
|
333
|
+
const handleActionResult = async (result) => {
|
|
334
|
+
// Handle ActionResults from background callbacks (e.g., conflict resolution completion)
|
|
335
|
+
// This allows showing dialogs even when not in the normal action flow
|
|
336
|
+
if (!popupsSupported)
|
|
337
|
+
return;
|
|
338
|
+
// Handle the result type and show appropriate dialog
|
|
339
|
+
if (result.type === "confirm") {
|
|
340
|
+
const confirmed = await popupManager.launchConfirmPopup(result.title || "Confirm", result.message, result.confirmLabel, result.cancelLabel);
|
|
341
|
+
if (confirmed && result.onConfirm) {
|
|
342
|
+
const nextResult = await result.onConfirm();
|
|
343
|
+
// Recursively handle nested results
|
|
344
|
+
if (nextResult) {
|
|
345
|
+
await handleActionResult(nextResult);
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
else if (!confirmed && result.onCancel) {
|
|
349
|
+
const nextResult = await result.onCancel();
|
|
350
|
+
if (nextResult) {
|
|
351
|
+
await handleActionResult(nextResult);
|
|
352
|
+
}
|
|
429
353
|
}
|
|
430
354
|
}
|
|
431
|
-
if (
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
const
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
/Yes\/No/i,
|
|
461
|
-
/\[Y\/n\]/i, // Default yes pattern
|
|
462
|
-
/press.*enter.*accept/i, // Press enter to accept
|
|
463
|
-
/press.*enter.*continue/i, // Press enter to continue
|
|
464
|
-
/❯\s*1\.\s*Yes,\s*proceed/i, // New Claude numbered menu format
|
|
465
|
-
/Enter to confirm.*Esc to exit/i, // New Claude confirmation format
|
|
466
|
-
/1\.\s*Yes,\s*proceed/i, // Yes proceed option
|
|
467
|
-
/2\.\s*No,\s*exit/i // No exit option
|
|
468
|
-
];
|
|
469
|
-
for (let i = 0; i < maxChecks; i++) {
|
|
470
|
-
await new Promise(resolve => setTimeout(resolve, checkInterval));
|
|
355
|
+
else if (result.type === "choice") {
|
|
356
|
+
if (!result.options || !result.onSelect)
|
|
357
|
+
return;
|
|
358
|
+
const selectedId = await popupManager.launchChoicePopup(result.title || "Choose Option", result.message, result.options);
|
|
359
|
+
if (selectedId) {
|
|
360
|
+
const nextResult = await result.onSelect(selectedId);
|
|
361
|
+
// Recursively handle nested results
|
|
362
|
+
if (nextResult) {
|
|
363
|
+
await handleActionResult(nextResult);
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
else if (result.type === "input") {
|
|
368
|
+
if (!result.onSubmit)
|
|
369
|
+
return;
|
|
370
|
+
const inputValue = await popupManager.launchInputPopup(result.title || "Input", result.message, result.placeholder, result.defaultValue);
|
|
371
|
+
if (inputValue !== null) {
|
|
372
|
+
const nextResult = await result.onSubmit(inputValue);
|
|
373
|
+
// Recursively handle nested results
|
|
374
|
+
if (nextResult) {
|
|
375
|
+
await handleActionResult(nextResult);
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
else if (result.type === "navigation") {
|
|
380
|
+
// Navigate to target pane if specified
|
|
381
|
+
if (result.targetPaneId) {
|
|
382
|
+
const targetPane = panes.find(p => p.id === result.targetPaneId);
|
|
383
|
+
if (targetPane) {
|
|
471
384
|
try {
|
|
472
|
-
|
|
473
|
-
const paneContent = capturePaneContent(paneInfo, 30);
|
|
474
|
-
if (i % 10 === 0) { // Log every 10 checks (every second)
|
|
475
|
-
}
|
|
476
|
-
// Check if content has stabilized (same for 3 checks = prompt is waiting)
|
|
477
|
-
if (paneContent === lastContent) {
|
|
478
|
-
stableContentCount++;
|
|
479
|
-
}
|
|
480
|
-
else {
|
|
481
|
-
stableContentCount = 0;
|
|
482
|
-
lastContent = paneContent;
|
|
483
|
-
}
|
|
484
|
-
// Look for trust prompt in the current content
|
|
485
|
-
const hasTrustPrompt = trustPromptPatterns.some(pattern => pattern.test(paneContent));
|
|
486
|
-
// Also check if we see specific Claude permission text
|
|
487
|
-
const hasClaudePermissionPrompt = paneContent.includes('Do you trust') ||
|
|
488
|
-
paneContent.includes('trust the files') ||
|
|
489
|
-
paneContent.includes('permission') ||
|
|
490
|
-
paneContent.includes('allow') ||
|
|
491
|
-
(paneContent.includes('folder') && paneContent.includes('?'));
|
|
492
|
-
if ((hasTrustPrompt || hasClaudePermissionPrompt) && !promptHandled) {
|
|
493
|
-
// Content is stable and we found a prompt
|
|
494
|
-
if (stableContentCount >= 2) {
|
|
495
|
-
// Check if this is the new Claude numbered menu format
|
|
496
|
-
const isNewClaudeFormat = /❯\s*1\.\s*Yes,\s*proceed/i.test(paneContent) ||
|
|
497
|
-
/Enter to confirm.*Esc to exit/i.test(paneContent);
|
|
498
|
-
if (isNewClaudeFormat) {
|
|
499
|
-
// For new Claude format, just press Enter to confirm default "Yes, proceed"
|
|
500
|
-
execSync(`tmux send-keys -t '${paneInfo}' Enter`, { stdio: 'pipe' });
|
|
501
|
-
}
|
|
502
|
-
else {
|
|
503
|
-
// Try multiple response methods for older formats
|
|
504
|
-
// Method 1: Send 'y' followed by Enter (most explicit)
|
|
505
|
-
execSync(`tmux send-keys -t '${paneInfo}' 'y'`, { stdio: 'pipe' });
|
|
506
|
-
await new Promise(resolve => setTimeout(resolve, 50));
|
|
507
|
-
execSync(`tmux send-keys -t '${paneInfo}' Enter`, { stdio: 'pipe' });
|
|
508
|
-
// Method 2: Just Enter (if it's a yes/no with default yes)
|
|
509
|
-
await new Promise(resolve => setTimeout(resolve, 100));
|
|
510
|
-
execSync(`tmux send-keys -t '${paneInfo}' Enter`, { stdio: 'pipe' });
|
|
511
|
-
}
|
|
512
|
-
// Mark as handled to avoid duplicate responses
|
|
513
|
-
promptHandled = true;
|
|
514
|
-
// Wait and check if prompt is gone
|
|
515
|
-
await new Promise(resolve => setTimeout(resolve, 500));
|
|
516
|
-
// Verify the prompt is gone
|
|
517
|
-
const updatedContent = capturePaneContent(paneInfo, 10);
|
|
518
|
-
// If trust prompt is gone, check if we need to resend the Claude command
|
|
519
|
-
const promptGone = !trustPromptPatterns.some(p => p.test(updatedContent));
|
|
520
|
-
if (promptGone) {
|
|
521
|
-
// Check if Claude is running or if we need to restart it
|
|
522
|
-
const claudeRunning = updatedContent.includes('Claude') ||
|
|
523
|
-
updatedContent.includes('claude') ||
|
|
524
|
-
updatedContent.includes('Assistant') ||
|
|
525
|
-
(prompt && updatedContent.includes(prompt.substring(0, Math.min(20, prompt.length))));
|
|
526
|
-
if (!claudeRunning && !updatedContent.includes('$')) {
|
|
527
|
-
await new Promise(resolve => setTimeout(resolve, 300));
|
|
528
|
-
execSync(`tmux send-keys -t '${paneInfo}' '${escapedCmd}'`, { stdio: 'pipe' });
|
|
529
|
-
execSync(`tmux send-keys -t '${paneInfo}' Enter`, { stdio: 'pipe' });
|
|
530
|
-
}
|
|
531
|
-
break;
|
|
532
|
-
}
|
|
533
|
-
}
|
|
534
|
-
}
|
|
535
|
-
// If we see Claude is already running without prompts, we're done
|
|
536
|
-
if (!hasTrustPrompt && !hasClaudePermissionPrompt &&
|
|
537
|
-
(paneContent.includes('Claude') || paneContent.includes('Assistant'))) {
|
|
538
|
-
break;
|
|
539
|
-
}
|
|
385
|
+
TmuxService.getInstance().selectPane(targetPane.paneId);
|
|
540
386
|
}
|
|
541
387
|
catch (error) {
|
|
542
|
-
|
|
388
|
+
console.error('[onActionResult] Failed to navigate to pane:', error);
|
|
543
389
|
}
|
|
544
390
|
}
|
|
545
|
-
};
|
|
546
|
-
// Start monitoring for trust prompt in background
|
|
547
|
-
autoApproveTrust().catch(err => {
|
|
548
|
-
});
|
|
549
|
-
}
|
|
550
|
-
// Keep focus on the new pane
|
|
551
|
-
execSync(`tmux select-pane -t '${paneInfo}'`, { stdio: 'pipe' });
|
|
552
|
-
// Save pane info
|
|
553
|
-
const newPane = {
|
|
554
|
-
id: `dmux-${Date.now()}`,
|
|
555
|
-
slug,
|
|
556
|
-
prompt: prompt || 'No initial prompt',
|
|
557
|
-
paneId: paneInfo,
|
|
558
|
-
worktreePath,
|
|
559
|
-
agent
|
|
560
|
-
};
|
|
561
|
-
const updatedPanes = [...panes, newPane];
|
|
562
|
-
await savePanes(updatedPanes);
|
|
563
|
-
// Switch back to the original pane (where dmux is running)
|
|
564
|
-
execSync(`tmux select-pane -t '${originalPaneId}'`, { stdio: 'pipe' });
|
|
565
|
-
// Re-set the title for the dmux pane
|
|
566
|
-
try {
|
|
567
|
-
execSync(`tmux select-pane -t '${originalPaneId}' -T "dmux-${projectName}"`, { stdio: 'pipe' });
|
|
568
|
-
}
|
|
569
|
-
catch {
|
|
570
|
-
// Ignore if setting title fails
|
|
571
|
-
}
|
|
572
|
-
// Clear the screen and redraw the UI
|
|
573
|
-
process.stdout.write('\x1b[2J\x1b[H');
|
|
574
|
-
// Reset the creating pane flag and refresh
|
|
575
|
-
setIsCreatingPane(false);
|
|
576
|
-
setStatusMessage('');
|
|
577
|
-
setNewPanePrompt('');
|
|
578
|
-
// Force a reload of panes to ensure UI is up to date
|
|
579
|
-
await loadPanes();
|
|
580
|
-
};
|
|
581
|
-
const jumpToPane = (paneId) => {
|
|
582
|
-
try {
|
|
583
|
-
// Enable pane borders to show titles (if not already enabled)
|
|
584
|
-
try {
|
|
585
|
-
execSync(`tmux set-option -g pane-border-status top`, { stdio: 'pipe' });
|
|
586
391
|
}
|
|
587
|
-
|
|
588
|
-
|
|
392
|
+
// Show message if dismissable
|
|
393
|
+
if (result.message && result.dismissable) {
|
|
394
|
+
await popupManager.launchProgressPopup(result.message, "info", 3000);
|
|
589
395
|
}
|
|
590
|
-
execSync(`tmux select-pane -t '${paneId}'`, { stdio: 'pipe' });
|
|
591
|
-
// Clear screen after jump to remove artifacts
|
|
592
|
-
clearScreen();
|
|
593
|
-
setStatusMessage('Jumped to pane');
|
|
594
|
-
setTimeout(() => setStatusMessage(''), 2000);
|
|
595
396
|
}
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
397
|
+
else if (result.type === "info" ||
|
|
398
|
+
result.type === "success" ||
|
|
399
|
+
result.type === "error") {
|
|
400
|
+
await popupManager.launchProgressPopup(result.message, result.type, 3000);
|
|
599
401
|
}
|
|
600
402
|
};
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
//
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
// For tests, monitor for completion
|
|
657
|
-
setTimeout(() => monitorTestOutput(pane.id, logFile), 2000);
|
|
658
|
-
}
|
|
659
|
-
else {
|
|
660
|
-
// For dev, monitor for server URL
|
|
661
|
-
setTimeout(() => monitorDevOutput(pane.id, logFile), 2000);
|
|
403
|
+
// Action system - initialized after services are defined
|
|
404
|
+
const actionSystem = useActionSystem({
|
|
405
|
+
panes,
|
|
406
|
+
savePanes,
|
|
407
|
+
sessionName,
|
|
408
|
+
projectName,
|
|
409
|
+
onPaneRemove: async (paneId) => {
|
|
410
|
+
// Mark pane as closing to prevent race condition with worker
|
|
411
|
+
await lifecycleManager.beginClose(paneId, 'user requested');
|
|
412
|
+
// Remove from panes list
|
|
413
|
+
const updatedPanes = panes.filter((p) => p.paneId !== paneId);
|
|
414
|
+
savePanes(updatedPanes);
|
|
415
|
+
// Mark close as completed (no more lock needed)
|
|
416
|
+
await lifecycleManager.completeClose(paneId);
|
|
417
|
+
},
|
|
418
|
+
onActionResult: handleActionResult,
|
|
419
|
+
forceRepaint,
|
|
420
|
+
popupLaunchers: popupsSupported
|
|
421
|
+
? {
|
|
422
|
+
launchConfirmPopup: popupManager.launchConfirmPopup.bind(popupManager),
|
|
423
|
+
launchChoicePopup: popupManager.launchChoicePopup.bind(popupManager),
|
|
424
|
+
launchInputPopup: popupManager.launchInputPopup.bind(popupManager),
|
|
425
|
+
launchProgressPopup: popupManager.launchProgressPopup.bind(popupManager),
|
|
426
|
+
}
|
|
427
|
+
: undefined,
|
|
428
|
+
});
|
|
429
|
+
// Auto-show new pane dialog removed - users can press 'n' to create panes via popup
|
|
430
|
+
// Periodic enforcement of control pane size and content pane rebalancing (left sidebar at 40 chars)
|
|
431
|
+
useLayoutManagement({
|
|
432
|
+
controlPaneId,
|
|
433
|
+
hasActiveDialog: actionSystem.actionState.showConfirmDialog ||
|
|
434
|
+
actionSystem.actionState.showChoiceDialog ||
|
|
435
|
+
actionSystem.actionState.showInputDialog ||
|
|
436
|
+
actionSystem.actionState.showProgressDialog ||
|
|
437
|
+
!!showCommandPrompt ||
|
|
438
|
+
showFileCopyPrompt ||
|
|
439
|
+
isCreatingPane ||
|
|
440
|
+
runningCommand ||
|
|
441
|
+
isUpdating,
|
|
442
|
+
onForceRepaint: forceRepaint,
|
|
443
|
+
});
|
|
444
|
+
// Monitor agent status across panes (returns a map of pane ID to status)
|
|
445
|
+
const agentStatuses = useAgentStatus({
|
|
446
|
+
panes,
|
|
447
|
+
suspend: actionSystem.actionState.showConfirmDialog ||
|
|
448
|
+
actionSystem.actionState.showChoiceDialog ||
|
|
449
|
+
actionSystem.actionState.showInputDialog ||
|
|
450
|
+
actionSystem.actionState.showProgressDialog ||
|
|
451
|
+
!!showCommandPrompt ||
|
|
452
|
+
showFileCopyPrompt,
|
|
453
|
+
onPaneRemoved: (paneId) => {
|
|
454
|
+
// Check if this pane is being closed intentionally or is locked
|
|
455
|
+
// If so, don't re-save - the close action already handled it
|
|
456
|
+
if (lifecycleManager.isClosing(paneId) || lifecycleManager.isLocked(paneId)) {
|
|
457
|
+
return;
|
|
662
458
|
}
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
setTimeout(() => setStatusMessage(''), 3000);
|
|
671
|
-
}
|
|
672
|
-
};
|
|
459
|
+
// Pane was removed unexpectedly (e.g., user killed tmux pane manually)
|
|
460
|
+
// Remove it from our tracking
|
|
461
|
+
const updatedPanes = panes.filter((p) => p.id !== paneId);
|
|
462
|
+
savePanes(updatedPanes);
|
|
463
|
+
},
|
|
464
|
+
});
|
|
465
|
+
// jumpToPane and runCommand functions removed - now handled by action system and pane runner
|
|
673
466
|
// Update handling moved to useAutoUpdater
|
|
674
|
-
//
|
|
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);
|
|
679
|
-
// Multiple clearing strategies to prevent artifacts
|
|
680
|
-
// 1. Clear screen with ANSI codes
|
|
681
|
-
process.stdout.write('\x1b[2J\x1b[H');
|
|
682
|
-
// 2. Clear tmux history
|
|
683
|
-
try {
|
|
684
|
-
execSync('tmux clear-history', { stdio: 'pipe' });
|
|
685
|
-
}
|
|
686
|
-
catch { }
|
|
687
|
-
// 3. Force tmux to refresh the display
|
|
688
|
-
try {
|
|
689
|
-
execSync('tmux refresh-client', { stdio: 'pipe' });
|
|
690
|
-
}
|
|
691
|
-
catch { }
|
|
692
|
-
};
|
|
467
|
+
// clearScreen function removed - no longer used (was only used by removed jumpToPane function)
|
|
693
468
|
// Cleanup function for exit
|
|
694
469
|
const cleanExit = () => {
|
|
695
470
|
// Clear screen before exiting Ink
|
|
696
|
-
process.stdout.write(
|
|
471
|
+
process.stdout.write("\x1b[2J\x1b[3J\x1b[H");
|
|
697
472
|
// Exit the Ink app (this cleans up the React tree)
|
|
698
473
|
exit();
|
|
699
474
|
// Give Ink a moment to clean up its rendering, then do final cleanup
|
|
700
|
-
setTimeout(() => {
|
|
475
|
+
setTimeout(async () => {
|
|
701
476
|
// Multiple aggressive clearing strategies
|
|
702
|
-
process.stdout.write(
|
|
703
|
-
process.stdout.write(
|
|
704
|
-
process.stdout.write(
|
|
477
|
+
process.stdout.write("\x1b[2J\x1b[H"); // Clear screen and move cursor to home
|
|
478
|
+
process.stdout.write("\x1b[3J"); // Clear scrollback buffer
|
|
479
|
+
process.stdout.write("\x1b[0m"); // Reset all attributes
|
|
705
480
|
// Clear tmux history and pane
|
|
706
481
|
try {
|
|
707
|
-
|
|
708
|
-
|
|
482
|
+
const tmuxService = TmuxService.getInstance();
|
|
483
|
+
tmuxService.clearHistorySync();
|
|
484
|
+
await tmuxService.sendKeys("", "C-l");
|
|
709
485
|
}
|
|
710
486
|
catch { }
|
|
711
487
|
// One more final clear
|
|
712
|
-
process.stdout.write(
|
|
488
|
+
process.stdout.write("\x1b[2J\x1b[H");
|
|
713
489
|
// Show clean goodbye message
|
|
714
|
-
process.stdout.write(
|
|
490
|
+
process.stdout.write("\n Run dmux again to resume. Goodbye 👋\n\n");
|
|
715
491
|
// Exit process
|
|
716
492
|
process.exit(0);
|
|
717
493
|
}, 100);
|
|
718
494
|
};
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
//
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
return;
|
|
780
|
-
}
|
|
781
|
-
// Allow other inputs to continue (don't return early)
|
|
782
|
-
}
|
|
783
|
-
// Handle QR code view
|
|
784
|
-
if (showQRCode) {
|
|
785
|
-
if (key.escape) {
|
|
786
|
-
setShowQRCode(false);
|
|
787
|
-
}
|
|
788
|
-
return;
|
|
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
|
-
}
|
|
957
|
-
// Handle action system confirm dialog
|
|
958
|
-
if (actionSystem.actionState.showConfirmDialog) {
|
|
959
|
-
if (key.escape) {
|
|
960
|
-
if (actionSystem.actionState.onConfirmNo) {
|
|
961
|
-
actionSystem.executeCallback(actionSystem.actionState.onConfirmNo);
|
|
962
|
-
}
|
|
963
|
-
else {
|
|
964
|
-
actionSystem.setActionState(prev => ({ ...prev, showConfirmDialog: false }));
|
|
965
|
-
}
|
|
966
|
-
return;
|
|
967
|
-
}
|
|
968
|
-
else if (key.upArrow) {
|
|
969
|
-
actionSystem.setActionState(prev => ({
|
|
970
|
-
...prev,
|
|
971
|
-
confirmSelectedIndex: Math.max(0, prev.confirmSelectedIndex - 1)
|
|
972
|
-
}));
|
|
973
|
-
return;
|
|
974
|
-
}
|
|
975
|
-
else if (key.downArrow) {
|
|
976
|
-
actionSystem.setActionState(prev => ({
|
|
977
|
-
...prev,
|
|
978
|
-
confirmSelectedIndex: Math.min(1, prev.confirmSelectedIndex + 1)
|
|
979
|
-
}));
|
|
980
|
-
return;
|
|
981
|
-
}
|
|
982
|
-
else if (key.return) {
|
|
983
|
-
// Execute based on selected index
|
|
984
|
-
if (actionSystem.actionState.confirmSelectedIndex === 0) {
|
|
985
|
-
if (actionSystem.actionState.onConfirmYes) {
|
|
986
|
-
actionSystem.executeCallback(actionSystem.actionState.onConfirmYes);
|
|
987
|
-
}
|
|
988
|
-
}
|
|
989
|
-
else {
|
|
990
|
-
if (actionSystem.actionState.onConfirmNo) {
|
|
991
|
-
actionSystem.executeCallback(actionSystem.actionState.onConfirmNo);
|
|
992
|
-
}
|
|
993
|
-
else {
|
|
994
|
-
actionSystem.setActionState(prev => ({ ...prev, showConfirmDialog: false }));
|
|
995
|
-
}
|
|
996
|
-
}
|
|
997
|
-
return;
|
|
998
|
-
}
|
|
999
|
-
else if (input === 'y' || input === 'Y') {
|
|
1000
|
-
// Shortcut: yes
|
|
1001
|
-
if (actionSystem.actionState.onConfirmYes) {
|
|
1002
|
-
actionSystem.executeCallback(actionSystem.actionState.onConfirmYes);
|
|
1003
|
-
}
|
|
1004
|
-
return;
|
|
1005
|
-
}
|
|
1006
|
-
else if (input === 'n' || input === 'N') {
|
|
1007
|
-
// Shortcut: no
|
|
1008
|
-
if (actionSystem.actionState.onConfirmNo) {
|
|
1009
|
-
actionSystem.executeCallback(actionSystem.actionState.onConfirmNo);
|
|
1010
|
-
}
|
|
1011
|
-
else {
|
|
1012
|
-
actionSystem.setActionState(prev => ({ ...prev, showConfirmDialog: false }));
|
|
1013
|
-
}
|
|
1014
|
-
return;
|
|
1015
|
-
}
|
|
1016
|
-
return;
|
|
1017
|
-
}
|
|
1018
|
-
// Handle action system input dialog
|
|
1019
|
-
if (actionSystem.actionState.showInputDialog) {
|
|
1020
|
-
if (key.escape) {
|
|
1021
|
-
actionSystem.setActionState(prev => ({ ...prev, showInputDialog: false }));
|
|
1022
|
-
return;
|
|
1023
|
-
}
|
|
1024
|
-
else if (key.return) {
|
|
1025
|
-
if (actionSystem.actionState.onInputSubmit) {
|
|
1026
|
-
actionSystem.executeCallback(async () => actionSystem.actionState.onInputSubmit(actionSystem.actionState.inputValue));
|
|
1027
|
-
}
|
|
1028
|
-
return;
|
|
1029
|
-
}
|
|
1030
|
-
// Let CleanTextInput handle all other key events
|
|
1031
|
-
return;
|
|
1032
|
-
}
|
|
1033
|
-
// Handle action system choice dialog
|
|
1034
|
-
if (actionSystem.actionState.showChoiceDialog) {
|
|
1035
|
-
if (key.escape) {
|
|
1036
|
-
actionSystem.setActionState(prev => ({ ...prev, showChoiceDialog: false }));
|
|
1037
|
-
return;
|
|
1038
|
-
}
|
|
1039
|
-
else if (key.upArrow) {
|
|
1040
|
-
actionSystem.setActionState(prev => ({
|
|
1041
|
-
...prev,
|
|
1042
|
-
choiceSelectedIndex: Math.max(0, prev.choiceSelectedIndex - 1)
|
|
1043
|
-
}));
|
|
1044
|
-
return;
|
|
1045
|
-
}
|
|
1046
|
-
else if (key.downArrow) {
|
|
1047
|
-
const maxIndex = actionSystem.actionState.choiceOptions.length - 1;
|
|
1048
|
-
actionSystem.setActionState(prev => ({
|
|
1049
|
-
...prev,
|
|
1050
|
-
choiceSelectedIndex: Math.min(maxIndex, prev.choiceSelectedIndex + 1)
|
|
1051
|
-
}));
|
|
1052
|
-
return;
|
|
1053
|
-
}
|
|
1054
|
-
else if (key.return) {
|
|
1055
|
-
const selectedOption = actionSystem.actionState.choiceOptions[actionSystem.actionState.choiceSelectedIndex];
|
|
1056
|
-
if (selectedOption && actionSystem.actionState.onChoiceSelect) {
|
|
1057
|
-
actionSystem.executeCallback(async () => actionSystem.actionState.onChoiceSelect(selectedOption.id));
|
|
1058
|
-
}
|
|
1059
|
-
return;
|
|
1060
|
-
}
|
|
1061
|
-
return;
|
|
1062
|
-
}
|
|
1063
|
-
if (showFileCopyPrompt) {
|
|
1064
|
-
if (input === 'y' || input === 'Y') {
|
|
1065
|
-
setShowFileCopyPrompt(false);
|
|
1066
|
-
const selectedPane = panes[selectedIndex];
|
|
1067
|
-
if (selectedPane && selectedPane.worktreePath && currentCommandType) {
|
|
1068
|
-
await copyNonGitFiles(selectedPane.worktreePath);
|
|
1069
|
-
// Mark as not first run and continue with command
|
|
1070
|
-
const newSettings = {
|
|
1071
|
-
...projectSettings,
|
|
1072
|
-
[currentCommandType === 'test' ? 'firstTestRun' : 'firstDevRun']: true
|
|
1073
|
-
};
|
|
1074
|
-
await saveSettings(newSettings);
|
|
1075
|
-
// Now run the actual command
|
|
1076
|
-
await runCommandInternal(currentCommandType, selectedPane);
|
|
1077
|
-
}
|
|
1078
|
-
setCurrentCommandType(null);
|
|
1079
|
-
}
|
|
1080
|
-
else if (input === 'n' || input === 'N' || key.escape) {
|
|
1081
|
-
setShowFileCopyPrompt(false);
|
|
1082
|
-
const selectedPane = panes[selectedIndex];
|
|
1083
|
-
if (selectedPane && currentCommandType) {
|
|
1084
|
-
// Mark as not first run and continue without copying
|
|
1085
|
-
const newSettings = {
|
|
1086
|
-
...projectSettings,
|
|
1087
|
-
[currentCommandType === 'test' ? 'firstTestRun' : 'firstDevRun']: true
|
|
1088
|
-
};
|
|
1089
|
-
await saveSettings(newSettings);
|
|
1090
|
-
// Now run the actual command
|
|
1091
|
-
await runCommandInternal(currentCommandType, selectedPane);
|
|
1092
|
-
}
|
|
1093
|
-
setCurrentCommandType(null);
|
|
1094
|
-
}
|
|
1095
|
-
return;
|
|
1096
|
-
}
|
|
1097
|
-
if (showAgentChoiceDialog) {
|
|
1098
|
-
if (key.escape) {
|
|
1099
|
-
setShowAgentChoiceDialog(false);
|
|
1100
|
-
setShowNewPaneDialog(true);
|
|
1101
|
-
setNewPanePrompt(pendingPrompt);
|
|
1102
|
-
setPendingPrompt('');
|
|
1103
|
-
}
|
|
1104
|
-
else if (key.leftArrow || input === '1' || (input && input.toLowerCase() === 'c')) {
|
|
1105
|
-
setAgentChoice('claude');
|
|
1106
|
-
}
|
|
1107
|
-
else if (key.rightArrow || input === '2' || (input && input.toLowerCase() === 'o')) {
|
|
1108
|
-
setAgentChoice('opencode');
|
|
1109
|
-
}
|
|
1110
|
-
else if (key.return) {
|
|
1111
|
-
const chosen = agentChoice || (availableAgents[0] || 'claude');
|
|
1112
|
-
const promptValue = pendingPrompt;
|
|
1113
|
-
setShowAgentChoiceDialog(false);
|
|
1114
|
-
setPendingPrompt('');
|
|
1115
|
-
await createNewPaneHook(promptValue, chosen);
|
|
1116
|
-
setNewPanePrompt('');
|
|
1117
|
-
}
|
|
1118
|
-
return;
|
|
1119
|
-
}
|
|
1120
|
-
if (showCommandPrompt) {
|
|
1121
|
-
if (key.escape) {
|
|
1122
|
-
setShowCommandPrompt(null);
|
|
1123
|
-
setCommandInput('');
|
|
1124
|
-
}
|
|
1125
|
-
else if (key.return) {
|
|
1126
|
-
if (commandInput.trim() === '') {
|
|
1127
|
-
// If empty, suggest a default command based on package manager
|
|
1128
|
-
const suggested = await suggestCommand(showCommandPrompt);
|
|
1129
|
-
if (suggested) {
|
|
1130
|
-
setCommandInput(suggested);
|
|
1131
|
-
}
|
|
1132
|
-
}
|
|
1133
|
-
else {
|
|
1134
|
-
// User provided manual command
|
|
1135
|
-
const newSettings = {
|
|
1136
|
-
...projectSettings,
|
|
1137
|
-
[showCommandPrompt === 'test' ? 'testCommand' : 'devCommand']: commandInput.trim()
|
|
1138
|
-
};
|
|
1139
|
-
await saveSettings(newSettings);
|
|
1140
|
-
const selectedPane = panes[selectedIndex];
|
|
1141
|
-
if (selectedPane) {
|
|
1142
|
-
// Check if first run
|
|
1143
|
-
const isFirstRun = showCommandPrompt === 'test' ? !projectSettings.firstTestRun : !projectSettings.firstDevRun;
|
|
1144
|
-
if (isFirstRun) {
|
|
1145
|
-
setCurrentCommandType(showCommandPrompt);
|
|
1146
|
-
setShowCommandPrompt(null);
|
|
1147
|
-
setShowFileCopyPrompt(true);
|
|
1148
|
-
}
|
|
1149
|
-
else {
|
|
1150
|
-
await runCommandInternal(showCommandPrompt, selectedPane);
|
|
1151
|
-
setShowCommandPrompt(null);
|
|
1152
|
-
setCommandInput('');
|
|
1153
|
-
}
|
|
1154
|
-
}
|
|
1155
|
-
else {
|
|
1156
|
-
setShowCommandPrompt(null);
|
|
1157
|
-
setCommandInput('');
|
|
1158
|
-
}
|
|
1159
|
-
}
|
|
1160
|
-
}
|
|
1161
|
-
return;
|
|
1162
|
-
}
|
|
1163
|
-
if (showNewPaneDialog) {
|
|
1164
|
-
if (key.escape) {
|
|
1165
|
-
setShowNewPaneDialog(false);
|
|
1166
|
-
setNewPanePrompt('');
|
|
1167
|
-
}
|
|
1168
|
-
// TextInput handles other input events
|
|
1169
|
-
return;
|
|
1170
|
-
}
|
|
1171
|
-
// Handle directional navigation with spatial awareness based on card grid layout
|
|
1172
|
-
if (key.upArrow || key.downArrow || key.leftArrow || key.rightArrow) {
|
|
1173
|
-
let targetIndex = null;
|
|
1174
|
-
if (key.upArrow) {
|
|
1175
|
-
targetIndex = findCardInDirection(selectedIndex, 'up');
|
|
1176
|
-
}
|
|
1177
|
-
else if (key.downArrow) {
|
|
1178
|
-
targetIndex = findCardInDirection(selectedIndex, 'down');
|
|
1179
|
-
}
|
|
1180
|
-
else if (key.leftArrow) {
|
|
1181
|
-
targetIndex = findCardInDirection(selectedIndex, 'left');
|
|
1182
|
-
}
|
|
1183
|
-
else if (key.rightArrow) {
|
|
1184
|
-
targetIndex = findCardInDirection(selectedIndex, 'right');
|
|
1185
|
-
}
|
|
1186
|
-
if (targetIndex !== null) {
|
|
1187
|
-
setSelectedIndex(targetIndex);
|
|
1188
|
-
}
|
|
1189
|
-
return;
|
|
1190
|
-
}
|
|
1191
|
-
if ((input === 'm' || key.return) && selectedIndex < panes.length) {
|
|
1192
|
-
// Open kebab menu for selected pane
|
|
1193
|
-
const selectedPane = panes[selectedIndex];
|
|
1194
|
-
const actions = getAvailableActions(selectedPane, projectSettings);
|
|
1195
|
-
setKebabMenuActions(actions);
|
|
1196
|
-
setShowKebabMenu(true);
|
|
1197
|
-
setKebabMenuPaneIndex(selectedIndex);
|
|
1198
|
-
setKebabMenuOption(0);
|
|
1199
|
-
}
|
|
1200
|
-
else if (input === 's') {
|
|
1201
|
-
// Open settings dialog
|
|
1202
|
-
setShowSettingsDialog(true);
|
|
1203
|
-
setSettingsMode('list');
|
|
1204
|
-
setSettingsSelectedIndex(0);
|
|
1205
|
-
}
|
|
1206
|
-
else if (input === 'q') {
|
|
1207
|
-
cleanExit();
|
|
1208
|
-
}
|
|
1209
|
-
else if (input === 'r' && server) {
|
|
1210
|
-
// Create tunnel if not already created, then show QR code
|
|
1211
|
-
if (!tunnelUrl) {
|
|
1212
|
-
setIsCreatingTunnel(true);
|
|
1213
|
-
setStatusMessage('Creating tunnel...');
|
|
1214
|
-
try {
|
|
1215
|
-
const url = await server.startTunnel();
|
|
1216
|
-
setTunnelUrl(url);
|
|
1217
|
-
setStatusMessage('');
|
|
1218
|
-
setShowQRCode(true);
|
|
1219
|
-
}
|
|
1220
|
-
catch (error) {
|
|
1221
|
-
setStatusMessage('Failed to create tunnel');
|
|
1222
|
-
setTimeout(() => setStatusMessage(''), 3000);
|
|
1223
|
-
}
|
|
1224
|
-
finally {
|
|
1225
|
-
setIsCreatingTunnel(false);
|
|
1226
|
-
}
|
|
1227
|
-
}
|
|
1228
|
-
else {
|
|
1229
|
-
// Tunnel already exists, just show the QR code
|
|
1230
|
-
setShowQRCode(true);
|
|
1231
|
-
}
|
|
495
|
+
// Input handling - extracted to dedicated hook
|
|
496
|
+
useInputHandling({
|
|
497
|
+
panes,
|
|
498
|
+
selectedIndex,
|
|
499
|
+
setSelectedIndex,
|
|
500
|
+
isCreatingPane,
|
|
501
|
+
setIsCreatingPane,
|
|
502
|
+
runningCommand,
|
|
503
|
+
isUpdating,
|
|
504
|
+
isLoading,
|
|
505
|
+
ignoreInput,
|
|
506
|
+
quitConfirmMode,
|
|
507
|
+
setQuitConfirmMode,
|
|
508
|
+
showCommandPrompt,
|
|
509
|
+
setShowCommandPrompt,
|
|
510
|
+
commandInput,
|
|
511
|
+
setCommandInput,
|
|
512
|
+
showFileCopyPrompt,
|
|
513
|
+
setShowFileCopyPrompt,
|
|
514
|
+
currentCommandType,
|
|
515
|
+
setCurrentCommandType,
|
|
516
|
+
projectSettings,
|
|
517
|
+
saveSettings,
|
|
518
|
+
settingsManager,
|
|
519
|
+
tunnelUrl,
|
|
520
|
+
setTunnelUrl,
|
|
521
|
+
tunnelCreating,
|
|
522
|
+
setTunnelCreating,
|
|
523
|
+
setTunnelCopied,
|
|
524
|
+
popupManager,
|
|
525
|
+
actionSystem,
|
|
526
|
+
server,
|
|
527
|
+
controlPaneId,
|
|
528
|
+
setStatusMessage,
|
|
529
|
+
copyNonGitFiles,
|
|
530
|
+
runCommandInternal,
|
|
531
|
+
handlePaneCreationWithAgent,
|
|
532
|
+
loadPanes,
|
|
533
|
+
cleanExit,
|
|
534
|
+
findCardInDirection,
|
|
535
|
+
});
|
|
536
|
+
// Calculate available height for content (terminal height - footer lines - active status messages)
|
|
537
|
+
// Footer height varies based on state:
|
|
538
|
+
// - Quit confirm mode: 2 lines (marginTop + 1 text line)
|
|
539
|
+
// - Normal mode calculation:
|
|
540
|
+
// - Base: 4 lines (marginTop + logs divider + logs line + keyboard shortcuts)
|
|
541
|
+
// - Network section: +4 lines (divider, local IP, remote tunnel, divider) if serverPort exists
|
|
542
|
+
// - Debug info: +1 line if DEBUG_DMUX
|
|
543
|
+
// - Status line: +1 line if updateAvailable/currentBranch/debugMessage
|
|
544
|
+
// - Status messages: +1 line per active message
|
|
545
|
+
let footerLines = 2;
|
|
546
|
+
if (quitConfirmMode) {
|
|
547
|
+
footerLines = 2;
|
|
548
|
+
}
|
|
549
|
+
else {
|
|
550
|
+
// Base footer (logs divider + logs + shortcuts - always shown)
|
|
551
|
+
footerLines = 4; // marginTop + logs divider + logs + shortcuts
|
|
552
|
+
// Add network section (now 2 lines for local IP + remote tunnel, plus 2 dividers)
|
|
553
|
+
if (serverPort && serverPort > 0) {
|
|
554
|
+
footerLines += 4;
|
|
1232
555
|
}
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
setShowNewPaneDialog(true);
|
|
1237
|
-
return; // Consume the 'n' keystroke so it doesn't propagate
|
|
556
|
+
// Add debug info
|
|
557
|
+
if (process.env.DEBUG_DMUX) {
|
|
558
|
+
footerLines += 1;
|
|
1238
559
|
}
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
setTimeout(() => StateManager.getInstance().setDebugMessage(''), 2000);
|
|
1243
|
-
actionSystem.executeAction(PaneAction.VIEW, panes[selectedIndex]);
|
|
560
|
+
// Add status line
|
|
561
|
+
if (updateAvailable || currentBranch || debugMessage) {
|
|
562
|
+
footerLines += 1;
|
|
1244
563
|
}
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
setTimeout(() => StateManager.getInstance().setDebugMessage(''), 2000);
|
|
1249
|
-
actionSystem.executeAction(PaneAction.CLOSE, panes[selectedIndex]);
|
|
564
|
+
// Add line for each active status message
|
|
565
|
+
if (statusMessage) {
|
|
566
|
+
footerLines += 1;
|
|
1250
567
|
}
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
StateManager.getInstance().setDebugMessage(`Jumping to pane: ${panes[selectedIndex].slug}`);
|
|
1254
|
-
setTimeout(() => StateManager.getInstance().setDebugMessage(''), 2000);
|
|
1255
|
-
actionSystem.executeAction(PaneAction.VIEW, panes[selectedIndex]);
|
|
568
|
+
if (actionSystem.actionState.statusMessage) {
|
|
569
|
+
footerLines += 1;
|
|
1256
570
|
}
|
|
1257
|
-
});
|
|
1258
|
-
// If showing QR code, render only that
|
|
1259
|
-
if (showQRCode && tunnelUrl) {
|
|
1260
|
-
return (React.createElement(Box, { flexDirection: "column" },
|
|
1261
|
-
React.createElement(Box, { marginBottom: 1 },
|
|
1262
|
-
React.createElement(Text, { bold: true, color: "cyan" }, "dmux - Remote Access")),
|
|
1263
|
-
React.createElement(QRCode, { url: tunnelUrl }),
|
|
1264
|
-
React.createElement(Box, { marginTop: 1 },
|
|
1265
|
-
React.createElement(Text, { dimColor: true }, "Press ESC to return to pane list"))));
|
|
1266
571
|
}
|
|
1267
|
-
|
|
572
|
+
const contentHeight = Math.max(terminalHeight - footerLines, 10);
|
|
573
|
+
return (React.createElement(Box, { flexDirection: "column", height: terminalHeight },
|
|
1268
574
|
showRepaintSpinner && (React.createElement(Box, { marginTop: -10, marginLeft: -100 },
|
|
1269
575
|
React.createElement(Text, null, "\u27F3"))),
|
|
1270
|
-
React.createElement(
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
createNewPaneHook(promptValue);
|
|
1279
|
-
}
|
|
1280
|
-
else if (agents.length === 1) {
|
|
1281
|
-
setShowNewPaneDialog(false);
|
|
1282
|
-
setNewPanePrompt('');
|
|
1283
|
-
createNewPaneHook(promptValue, agents[0]);
|
|
1284
|
-
}
|
|
1285
|
-
else {
|
|
1286
|
-
setPendingPrompt(promptValue);
|
|
1287
|
-
setShowNewPaneDialog(false);
|
|
1288
|
-
setNewPanePrompt('');
|
|
1289
|
-
setShowAgentChoiceDialog(true);
|
|
1290
|
-
setAgentChoice(agentChoice || 'claude');
|
|
1291
|
-
}
|
|
1292
|
-
} })),
|
|
1293
|
-
showAgentChoiceDialog && (React.createElement(AgentChoiceDialog, { agentChoice: agentChoice })),
|
|
1294
|
-
isCreatingPane && (React.createElement(CreatingIndicator, { message: statusMessage })),
|
|
1295
|
-
showCommandPrompt && (React.createElement(CommandPromptDialog, { type: showCommandPrompt, value: commandInput, onChange: setCommandInput })),
|
|
1296
|
-
showFileCopyPrompt && (React.createElement(FileCopyPrompt, null)),
|
|
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 })),
|
|
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 })),
|
|
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 })),
|
|
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) => {
|
|
1303
|
-
actionSystem.setActionState(prev => ({ ...prev, inputValue: value }));
|
|
1304
|
-
} })),
|
|
1305
|
-
actionSystem.actionState.showProgressDialog && (React.createElement(ActionProgressDialog, { key: "progress-dialog", message: actionSystem.actionState.progressMessage, percent: actionSystem.actionState.progressPercent })),
|
|
1306
|
-
runningCommand && (React.createElement(RunningIndicator, null)),
|
|
1307
|
-
isUpdating && (React.createElement(UpdatingIndicator, null)),
|
|
1308
|
-
isCreatingTunnel && (React.createElement(Box, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", padding: 1, marginTop: 1 },
|
|
1309
|
-
React.createElement(Text, { bold: true, color: "cyan" }, "Creating tunnel..."),
|
|
1310
|
-
React.createElement(Box, { marginTop: 1 },
|
|
1311
|
-
React.createElement(Text, { dimColor: true }, "This may take a few moments...")))),
|
|
1312
|
-
statusMessage && (React.createElement(Box, { marginTop: 1 },
|
|
576
|
+
React.createElement(Box, { flexDirection: "column", height: contentHeight, overflow: "hidden" },
|
|
577
|
+
React.createElement(PanesGrid, { panes: panes, selectedIndex: selectedIndex, isLoading: isLoading, agentStatuses: agentStatuses }),
|
|
578
|
+
isLoading && React.createElement(LoadingIndicator, null),
|
|
579
|
+
showCommandPrompt && (React.createElement(CommandPromptDialog, { type: showCommandPrompt, value: commandInput, onChange: setCommandInput })),
|
|
580
|
+
showFileCopyPrompt && React.createElement(FileCopyPrompt, null),
|
|
581
|
+
runningCommand && React.createElement(RunningIndicator, null),
|
|
582
|
+
isUpdating && React.createElement(UpdatingIndicator, null)),
|
|
583
|
+
statusMessage && (React.createElement(Box, null,
|
|
1313
584
|
React.createElement(Text, { color: "green" }, statusMessage))),
|
|
1314
|
-
actionSystem.actionState.statusMessage && (React.createElement(Box,
|
|
1315
|
-
React.createElement(Text, { color: actionSystem.actionState.statusType ===
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
585
|
+
actionSystem.actionState.statusMessage && (React.createElement(Box, null,
|
|
586
|
+
React.createElement(Text, { color: actionSystem.actionState.statusType === "error"
|
|
587
|
+
? "red"
|
|
588
|
+
: actionSystem.actionState.statusType === "success"
|
|
589
|
+
? "green"
|
|
590
|
+
: "cyan" }, actionSystem.actionState.statusMessage))),
|
|
591
|
+
React.createElement(FooterHelp, { show: !showCommandPrompt, showRemoteKey: !!server, quitConfirmMode: quitConfirmMode, hasSidebarLayout: !!controlPaneId, serverPort: serverPort, unreadErrorCount: unreadErrorCount, unreadWarningCount: unreadWarningCount, localIp: localIp, tunnelUrl: tunnelUrl, tunnelCreating: tunnelCreating, tunnelCopied: tunnelCopied, tunnelSpinner: tunnelState.getSpinnerChar(), gridInfo: (() => {
|
|
1319
592
|
if (!process.env.DEBUG_DMUX)
|
|
1320
593
|
return undefined;
|
|
1321
594
|
const cols = Math.max(1, Math.floor(terminalWidth / 37));
|
|
@@ -1323,16 +596,14 @@ const DmuxApp = ({ panesFile, projectName, sessionName, settingsFile, projectRoo
|
|
|
1323
596
|
const pos = getCardGridPosition(selectedIndex);
|
|
1324
597
|
return `Grid: ${cols} cols × ${rows} rows | Selected: row ${pos.row}, col ${pos.col} | Terminal: ${terminalWidth}w`;
|
|
1325
598
|
})() }),
|
|
1326
|
-
React.createElement(Text, { dimColor: true },
|
|
1327
|
-
updateAvailable && updateInfo && (React.createElement(Text, { color: "red", bold: true },
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
"
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
serverPort))),
|
|
1335
|
-
debugMessage && (React.createElement(Text, { dimColor: true },
|
|
599
|
+
(updateAvailable || currentBranch || debugMessage) && (React.createElement(Text, { dimColor: true },
|
|
600
|
+
updateAvailable && updateInfo && (React.createElement(Text, { color: "red", bold: true },
|
|
601
|
+
"Update available: npm i -g dmux@latest",
|
|
602
|
+
" ")),
|
|
603
|
+
currentBranch && (React.createElement(Text, { color: "magenta", bold: true },
|
|
604
|
+
"branch: ",
|
|
605
|
+
currentBranch)),
|
|
606
|
+
debugMessage && React.createElement(Text, { dimColor: true },
|
|
1336
607
|
" \u2022 ",
|
|
1337
608
|
debugMessage)))));
|
|
1338
609
|
};
|