startall 0.0.21 → 0.0.23

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 +2 -0
  2. package/index.js +94 -0
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -43,6 +43,7 @@ Traditional solutions fall short:
43
43
  - Per-process visibility toggles (`Space` or `1-9`)
44
44
  - Per-pane filters (different views in each pane)
45
45
  - **Custom pane naming**: Label panes for easier identification (`n`)
46
+ - **Column view**: Instant one-pane-per-script layout with `=` key (toggle back to restore your layout)
46
47
  - **Persistent layouts**: Your pane configuration is saved between sessions
47
48
  - **Process-specific views**: Show/hide specific processes in each pane
48
49
  - **Colored output**: Each process gets unique color-coded output
@@ -122,6 +123,7 @@ That's it! The TUI will:
122
123
  - `\` - Open command palette
123
124
  - `|` - Split pane vertically (left/right)
124
125
  - `_` - Split pane horizontally (top/bottom)
126
+ - `=` - Toggle column view (one column per script, auto-generated)
125
127
  - `x` - Close current pane (if >1 pane exists)
126
128
  - `Tab` - Next pane
127
129
  - `Shift+Tab` - Previous pane
package/index.js CHANGED
@@ -606,6 +606,10 @@ class ProcessManager {
606
606
  this.paneLineCount = new Map(); // Track how many lines we've rendered per pane
607
607
  this.uiJustRebuilt = false; // Flag to skip redundant render after buildRunningUI
608
608
 
609
+ // Column view state (one pane per script, side by side)
610
+ this.isColumnView = false; // Whether column view is active
611
+ this.savedPaneRoot = null; // Saved pane tree to restore when toggling back
612
+
609
613
  // Copy mode state (select text to copy)
610
614
  this.isCopyMode = false; // Whether in copy/select mode
611
615
  this.copyModeCursor = 0; // Current cursor line index within visible lines
@@ -660,6 +664,16 @@ class ProcessManager {
660
664
  return;
661
665
  }
662
666
 
667
+ // Handle Ctrl+L - clear screen buffer and redraw
668
+ if (key.ctrl && key.name === 'l') {
669
+ if (this.phase === 'running') {
670
+ this.outputLines = [];
671
+ this.totalLinesReceived = 0;
672
+ this.buildRunningUI();
673
+ }
674
+ return;
675
+ }
676
+
663
677
  this.handleInput(key.name, key);
664
678
  this.render();
665
679
  });
@@ -832,14 +846,17 @@ class ProcessManager {
832
846
  this.buildRunningUI();
833
847
  } else if (keyName === '|') {
834
848
  // Quick vertical split
849
+ this.exitColumnViewMode();
835
850
  this.splitCurrentPane('vertical');
836
851
  this.buildRunningUI();
837
852
  } else if (keyName === '_') {
838
853
  // Quick horizontal split
854
+ this.exitColumnViewMode();
839
855
  this.splitCurrentPane('horizontal');
840
856
  this.buildRunningUI();
841
857
  } else if (keyName === 'x' && getAllPaneIds(this.paneRoot).length > 1) {
842
858
  // Close current pane (only if more than one)
859
+ this.exitColumnViewMode();
843
860
  this.closeCurrentPane();
844
861
  this.buildRunningUI();
845
862
  } else if (keyName === 'space') {
@@ -975,6 +992,9 @@ class ProcessManager {
975
992
  } else if (keyName === 'y') {
976
993
  // Enter copy mode (select text to copy)
977
994
  this.enterCopyMode();
995
+ } else if (keyName === '=') {
996
+ // Toggle column view (one pane per script)
997
+ this.toggleColumnView();
978
998
  } else if (keyName === 'g' && IS_GIT_REPO) {
979
999
  // Open git modal (commit & push)
980
1000
  this.openGitModal();
@@ -1664,6 +1684,67 @@ class ProcessManager {
1664
1684
  }
1665
1685
  }
1666
1686
 
1687
+ // Generate a column view pane tree: one pane per running script, side by side
1688
+ generateColumnViewPaneTree() {
1689
+ // Get the scripts that are currently selected/running
1690
+ const runningScripts = this.scripts.filter(s => {
1691
+ const proc = this.processes.get(s.name);
1692
+ return proc && (proc.status === 'running' || proc.status === 'crashed' || proc.status === 'exited');
1693
+ });
1694
+
1695
+ if (runningScripts.length === 0) {
1696
+ return createPane([]);
1697
+ }
1698
+
1699
+ if (runningScripts.length === 1) {
1700
+ return createPane([runningScripts[0].name]);
1701
+ }
1702
+
1703
+ // Create a vertical split with one pane per script
1704
+ const panes = runningScripts.map(s => {
1705
+ const pane = createPane([s.name]);
1706
+ pane.name = s.displayName;
1707
+ return pane;
1708
+ });
1709
+
1710
+ return createSplit('vertical', panes);
1711
+ }
1712
+
1713
+ // Toggle between column view (one pane per script) and the normal saved layout
1714
+ toggleColumnView() {
1715
+ if (this.isColumnView) {
1716
+ // Restore the saved pane tree
1717
+ if (this.savedPaneRoot) {
1718
+ this.paneRoot = this.savedPaneRoot;
1719
+ this.savedPaneRoot = null;
1720
+ } else {
1721
+ this.paneRoot = createPane([]);
1722
+ }
1723
+ this.isColumnView = false;
1724
+ } else {
1725
+ // Save current pane tree and switch to column view
1726
+ this.savedPaneRoot = this.paneRoot;
1727
+ this.paneRoot = this.generateColumnViewPaneTree();
1728
+ this.isColumnView = true;
1729
+ }
1730
+
1731
+ // Focus the first pane in the new tree
1732
+ const allPanes = getAllPaneIds(this.paneRoot);
1733
+ if (allPanes.length > 0) {
1734
+ this.focusedPaneId = allPanes[0];
1735
+ }
1736
+
1737
+ this.buildRunningUI();
1738
+ }
1739
+
1740
+ // Exit column view mode without restoring saved layout (e.g. user manually split/closed a pane)
1741
+ exitColumnViewMode() {
1742
+ if (this.isColumnView) {
1743
+ this.isColumnView = false;
1744
+ this.savedPaneRoot = null;
1745
+ }
1746
+ }
1747
+
1667
1748
  // Move the currently selected process to the focused pane
1668
1749
  moveProcessToCurrentPane() {
1669
1750
  const scriptName = this.scripts[this.selectedIndex]?.name;
@@ -1750,6 +1831,8 @@ class ProcessManager {
1750
1831
 
1751
1832
  // Save the current pane layout to config (debounced to avoid excessive disk writes)
1752
1833
  savePaneLayout() {
1834
+ // Don't save the auto-generated column view layout - it's transient
1835
+ if (this.isColumnView) return;
1753
1836
  this.config.paneLayout = serializePaneTree(this.paneRoot);
1754
1837
  debouncedSaveConfig(this.config);
1755
1838
  }
@@ -4166,6 +4249,15 @@ class ProcessManager {
4166
4249
  });
4167
4250
  leftSide.add(statusIndicator);
4168
4251
 
4252
+ // Column view indicator
4253
+ if (this.isColumnView) {
4254
+ const columnIndicator = new TextRenderable(this.renderer, {
4255
+ id: 'column-view-indicator',
4256
+ content: t`${fg(COLORS.cyan)('COLUMNS')}`,
4257
+ });
4258
+ leftSide.add(columnIndicator);
4259
+ }
4260
+
4169
4261
  // Git branch indicator
4170
4262
  if (IS_GIT_REPO) {
4171
4263
  const branch = this.gitBranch || getGitBranch();
@@ -4276,6 +4368,7 @@ class ProcessManager {
4276
4368
  // Pane & navigation
4277
4369
  [
4278
4370
  { key: '\\', desc: 'panes', color: COLORS.cyan },
4371
+ { key: '=', desc: this.isColumnView ? 'merged' : 'columns', color: COLORS.cyan },
4279
4372
  { key: '1-9', desc: 'toggle', color: COLORS.success },
4280
4373
  ],
4281
4374
  // Process control
@@ -4290,6 +4383,7 @@ class ProcessManager {
4290
4383
  { key: '/', desc: 'filter', color: COLORS.cyan },
4291
4384
  { key: 'c', desc: 'color', color: COLORS.magenta },
4292
4385
  { key: 'y', desc: 'copy', color: COLORS.accent },
4386
+ { key: '^L', desc: 'clear', color: COLORS.cyan },
4293
4387
  ],
4294
4388
  // Misc
4295
4389
  [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "startall",
3
- "version": "0.0.21",
3
+ "version": "0.0.23",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "bin": {