startall 0.0.14 → 0.0.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +11 -3
  2. package/index.js +150 -0
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -56,10 +56,12 @@ Traditional solutions fall short:
56
56
  - **Quick process toggle**: Use number keys `1-9` for instant visibility control
57
57
 
58
58
  ### 🔧 Advanced Controls
59
- - **Quick Commands**: Assign keyboard shortcuts to run scripts on-demand
60
- - Press assigned key to run command in a popup overlay
59
+ - **Quick Commands**: Run any script on-demand without adding it to the persistent processes
60
+ - Press `e` to open command picker and select any script
61
+ - Or assign keyboard shortcuts for instant access (press assigned key to run)
61
62
  - Perfect for build scripts, tests, or any short-running command
62
- - Configure in settings (`o` Quick Commands section)
63
+ - Output shown in popup overlay with Esc to close
64
+ - Configure shortcuts in settings (`o` → Quick Commands section)
63
65
  - **Interactive input mode**: Send commands to running processes via stdin (`i`)
64
66
  - Perfect for dev servers that accept commands (Vite, Rust watch, etc.)
65
67
  - **Settings panel**: Configure ignore/include patterns, shortcuts, and more (`o`)
@@ -107,6 +109,7 @@ That's it! The TUI will:
107
109
  - `s` - Stop/start selected process
108
110
  - `r` - Restart selected process
109
111
  - `i` - Send input to selected process (interactive mode)
112
+ - `e` - Execute any script (opens command picker)
110
113
  - `a-z` - Run assigned quick command (if configured)
111
114
 
112
115
  *Pane Management:*
@@ -150,6 +153,11 @@ That's it! The TUI will:
150
153
  - `d` or `Backspace` - Delete pattern or shortcut
151
154
  - `Esc` or `q` - Return to previous screen
152
155
 
156
+ **Run Command Picker:**
157
+ - `↑`/`↓` or `k`/`j` - Navigate scripts
158
+ - `Enter` - Run selected script
159
+ - `Esc` or `q` - Close picker
160
+
153
161
  **Quick Commands Overlay:**
154
162
  - `Esc` - Close overlay and stop command (if running)
155
163
 
package/index.js CHANGED
@@ -379,6 +379,10 @@ class ProcessManager {
379
379
  this.commandOverlayScript = ''; // Script name being executed
380
380
  this.commandOverlayStatus = 'running'; // 'running' | 'exited' | 'crashed'
381
381
  this.commandOverlayProcess = null; // Process reference
382
+
383
+ // Run command modal state
384
+ this.showRunCommandModal = false; // Whether the run command picker is visible
385
+ this.runCommandModalIndex = 0; // Selected index in the modal
382
386
  this.outputBox = null; // Reference to the output container
383
387
  this.destroyed = false; // Flag to prevent operations after cleanup
384
388
  this.lastRenderedLineCount = 0; // Track how many lines we've rendered
@@ -494,6 +498,12 @@ class ProcessManager {
494
498
  return;
495
499
  }
496
500
 
501
+ // Handle run command modal
502
+ if (this.showRunCommandModal) {
503
+ this.handleRunCommandModalInput(keyName, keyEvent);
504
+ return;
505
+ }
506
+
497
507
  // Handle split menu
498
508
  if (this.showSplitMenu) {
499
509
  this.handleSplitMenuInput(keyName, keyEvent);
@@ -708,6 +718,11 @@ class ProcessManager {
708
718
  this.inputModeText = '';
709
719
  this.buildRunningUI();
710
720
  }
721
+ } else if (keyName === 'e') {
722
+ // Open run command modal
723
+ this.showRunCommandModal = true;
724
+ this.runCommandModalIndex = 0;
725
+ this.buildRunningUI();
711
726
  } else if (keyName && keyName.length === 1 && !keyEvent.ctrl && !keyEvent.meta && !keyEvent.shift) {
712
727
  // Check if this key is a custom shortcut
713
728
  const shortcuts = this.config.shortcuts || {};
@@ -1266,6 +1281,28 @@ class ProcessManager {
1266
1281
  }
1267
1282
  }
1268
1283
 
1284
+ handleRunCommandModalInput(keyName, keyEvent) {
1285
+ if (keyName === 'escape' || keyName === 'q') {
1286
+ this.showRunCommandModal = false;
1287
+ this.buildRunningUI();
1288
+ return;
1289
+ }
1290
+
1291
+ if (keyName === 'up' || keyName === 'k') {
1292
+ this.runCommandModalIndex = Math.max(0, this.runCommandModalIndex - 1);
1293
+ this.buildRunningUI();
1294
+ } else if (keyName === 'down' || keyName === 'j') {
1295
+ this.runCommandModalIndex = Math.min(this.allScripts.length - 1, this.runCommandModalIndex + 1);
1296
+ this.buildRunningUI();
1297
+ } else if (keyName === 'enter' || keyName === 'return') {
1298
+ const selectedScript = this.allScripts[this.runCommandModalIndex];
1299
+ if (selectedScript) {
1300
+ this.showRunCommandModal = false;
1301
+ this.executeCommand(selectedScript.name);
1302
+ }
1303
+ }
1304
+ }
1305
+
1269
1306
  getSplitMenuItems() {
1270
1307
  const allPanes = getAllPaneIds(this.paneRoot);
1271
1308
  const items = [
@@ -2674,6 +2711,114 @@ class ProcessManager {
2674
2711
  parent.add(overlay);
2675
2712
  }
2676
2713
 
2714
+ // Build run command picker modal
2715
+ buildRunCommandModal(parent) {
2716
+ // Create centered overlay
2717
+ const overlay = new BoxRenderable(this.renderer, {
2718
+ id: 'run-command-modal',
2719
+ position: 'absolute',
2720
+ top: '20%',
2721
+ left: '25%',
2722
+ width: '50%',
2723
+ height: '60%',
2724
+ backgroundColor: COLORS.bgLight,
2725
+ border: true,
2726
+ borderStyle: 'rounded',
2727
+ borderColor: COLORS.accent,
2728
+ title: ' Run Command ',
2729
+ padding: 1,
2730
+ flexDirection: 'column',
2731
+ });
2732
+
2733
+ // Scrollable list of scripts
2734
+ const listBox = new ScrollBoxRenderable(this.renderer, {
2735
+ id: 'run-command-list',
2736
+ height: Math.floor(this.renderer.height * 0.6) - 4,
2737
+ scrollX: false,
2738
+ scrollY: true,
2739
+ focusable: true,
2740
+ style: {
2741
+ rootOptions: {
2742
+ flexGrow: 1,
2743
+ backgroundColor: COLORS.bgLight,
2744
+ },
2745
+ contentOptions: {
2746
+ backgroundColor: COLORS.bgLight,
2747
+ width: '100%',
2748
+ },
2749
+ },
2750
+ });
2751
+
2752
+ this.allScripts.forEach((script, idx) => {
2753
+ const isFocused = idx === this.runCommandModalIndex;
2754
+ const indicator = isFocused ? '>' : ' ';
2755
+ const bgColor = isFocused ? COLORS.bgHighlight : null;
2756
+ const processColor = this.processColors.get(script.name) || COLORS.text;
2757
+
2758
+ // Check if this script has a shortcut
2759
+ const shortcuts = this.config.shortcuts || {};
2760
+ let shortcutKey = null;
2761
+ for (const [key, scriptName] of Object.entries(shortcuts)) {
2762
+ if (scriptName === script.name) {
2763
+ shortcutKey = key;
2764
+ break;
2765
+ }
2766
+ }
2767
+
2768
+ const itemContainer = new BoxRenderable(this.renderer, {
2769
+ id: `run-cmd-item-${idx}`,
2770
+ backgroundColor: bgColor,
2771
+ paddingLeft: 1,
2772
+ });
2773
+
2774
+ let content;
2775
+ if (shortcutKey) {
2776
+ content = t`${fg(isFocused ? COLORS.accent : COLORS.textDim)(indicator)} ${fg(processColor)(script.displayName)} ${fg(COLORS.textDim)(`(${shortcutKey})`)}`;
2777
+ } else {
2778
+ content = t`${fg(isFocused ? COLORS.accent : COLORS.textDim)(indicator)} ${fg(processColor)(script.displayName)}`;
2779
+ }
2780
+
2781
+ const itemText = new TextRenderable(this.renderer, {
2782
+ id: `run-cmd-text-${idx}`,
2783
+ content: content,
2784
+ });
2785
+
2786
+ itemContainer.add(itemText);
2787
+ listBox.content.add(itemContainer);
2788
+ });
2789
+
2790
+ // Auto-scroll to focused item
2791
+ if (listBox.scrollTo) {
2792
+ const lineHeight = 1;
2793
+ const viewportHeight = Math.floor(this.renderer.height * 0.6) - 4;
2794
+ const focusedY = this.runCommandModalIndex * lineHeight;
2795
+ if (focusedY < listBox.scrollTop || focusedY >= listBox.scrollTop + viewportHeight) {
2796
+ listBox.scrollTo({ x: 0, y: Math.max(0, focusedY - Math.floor(viewportHeight / 2)) });
2797
+ }
2798
+ }
2799
+
2800
+ overlay.add(listBox);
2801
+
2802
+ // Footer hint
2803
+ const hintBar = new BoxRenderable(this.renderer, {
2804
+ id: 'run-cmd-hint-bar',
2805
+ border: ['top'],
2806
+ borderStyle: 'single',
2807
+ borderColor: COLORS.border,
2808
+ paddingTop: 1,
2809
+ paddingLeft: 1,
2810
+ });
2811
+
2812
+ const hint = new TextRenderable(this.renderer, {
2813
+ id: 'run-cmd-hint',
2814
+ content: t`${fg(COLORS.textDim)('↑/↓ navigate')} ${fg(COLORS.accent)('Enter')} ${fg(COLORS.textDim)('run')} ${fg(COLORS.accent)('Esc')} ${fg(COLORS.textDim)('close')}`,
2815
+ });
2816
+ hintBar.add(hint);
2817
+ overlay.add(hintBar);
2818
+
2819
+ parent.add(overlay);
2820
+ }
2821
+
2677
2822
  buildRunningUI() {
2678
2823
  // Save scroll positions before destroying
2679
2824
  for (const [paneId, scrollBox] of this.paneScrollBoxes.entries()) {
@@ -2901,6 +3046,11 @@ class ProcessManager {
2901
3046
  this.buildSplitMenuOverlay(mainContainer);
2902
3047
  }
2903
3048
 
3049
+ // Add run command modal if active
3050
+ if (this.showRunCommandModal) {
3051
+ this.buildRunCommandModal(mainContainer);
3052
+ }
3053
+
2904
3054
  // Add command output overlay if active
2905
3055
  if (this.showCommandOverlay) {
2906
3056
  this.buildCommandOverlay(mainContainer);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "startall",
3
- "version": "0.0.14",
3
+ "version": "0.0.15",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "bin": {