startall 0.0.22 → 0.0.24
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/README.md +2 -0
- package/index.js +129 -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
|
@@ -429,6 +429,15 @@ function gitPush() {
|
|
|
429
429
|
}
|
|
430
430
|
}
|
|
431
431
|
|
|
432
|
+
function gitPull() {
|
|
433
|
+
try {
|
|
434
|
+
const output = execSync('git pull', { stdio: 'pipe', windowsHide: true, timeout: 30000 }).toString().trim();
|
|
435
|
+
return { success: true, output: output || 'Pulled successfully' };
|
|
436
|
+
} catch (err) {
|
|
437
|
+
return { success: false, error: err.stderr?.toString() || err.message };
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
|
|
432
441
|
// Detect git repo once at startup
|
|
433
442
|
const IS_GIT_REPO = isGitRepo();
|
|
434
443
|
|
|
@@ -606,6 +615,10 @@ class ProcessManager {
|
|
|
606
615
|
this.paneLineCount = new Map(); // Track how many lines we've rendered per pane
|
|
607
616
|
this.uiJustRebuilt = false; // Flag to skip redundant render after buildRunningUI
|
|
608
617
|
|
|
618
|
+
// Column view state (one pane per script, side by side)
|
|
619
|
+
this.isColumnView = false; // Whether column view is active
|
|
620
|
+
this.savedPaneRoot = null; // Saved pane tree to restore when toggling back
|
|
621
|
+
|
|
609
622
|
// Copy mode state (select text to copy)
|
|
610
623
|
this.isCopyMode = false; // Whether in copy/select mode
|
|
611
624
|
this.copyModeCursor = 0; // Current cursor line index within visible lines
|
|
@@ -842,14 +855,17 @@ class ProcessManager {
|
|
|
842
855
|
this.buildRunningUI();
|
|
843
856
|
} else if (keyName === '|') {
|
|
844
857
|
// Quick vertical split
|
|
858
|
+
this.exitColumnViewMode();
|
|
845
859
|
this.splitCurrentPane('vertical');
|
|
846
860
|
this.buildRunningUI();
|
|
847
861
|
} else if (keyName === '_') {
|
|
848
862
|
// Quick horizontal split
|
|
863
|
+
this.exitColumnViewMode();
|
|
849
864
|
this.splitCurrentPane('horizontal');
|
|
850
865
|
this.buildRunningUI();
|
|
851
866
|
} else if (keyName === 'x' && getAllPaneIds(this.paneRoot).length > 1) {
|
|
852
867
|
// Close current pane (only if more than one)
|
|
868
|
+
this.exitColumnViewMode();
|
|
853
869
|
this.closeCurrentPane();
|
|
854
870
|
this.buildRunningUI();
|
|
855
871
|
} else if (keyName === 'space') {
|
|
@@ -985,6 +1001,9 @@ class ProcessManager {
|
|
|
985
1001
|
} else if (keyName === 'y') {
|
|
986
1002
|
// Enter copy mode (select text to copy)
|
|
987
1003
|
this.enterCopyMode();
|
|
1004
|
+
} else if (keyName === '=') {
|
|
1005
|
+
// Toggle column view (one pane per script)
|
|
1006
|
+
this.toggleColumnView();
|
|
988
1007
|
} else if (keyName === 'g' && IS_GIT_REPO) {
|
|
989
1008
|
// Open git modal (commit & push)
|
|
990
1009
|
this.openGitModal();
|
|
@@ -1674,6 +1693,67 @@ class ProcessManager {
|
|
|
1674
1693
|
}
|
|
1675
1694
|
}
|
|
1676
1695
|
|
|
1696
|
+
// Generate a column view pane tree: one pane per running script, side by side
|
|
1697
|
+
generateColumnViewPaneTree() {
|
|
1698
|
+
// Get the scripts that are currently selected/running
|
|
1699
|
+
const runningScripts = this.scripts.filter(s => {
|
|
1700
|
+
const proc = this.processes.get(s.name);
|
|
1701
|
+
return proc && (proc.status === 'running' || proc.status === 'crashed' || proc.status === 'exited');
|
|
1702
|
+
});
|
|
1703
|
+
|
|
1704
|
+
if (runningScripts.length === 0) {
|
|
1705
|
+
return createPane([]);
|
|
1706
|
+
}
|
|
1707
|
+
|
|
1708
|
+
if (runningScripts.length === 1) {
|
|
1709
|
+
return createPane([runningScripts[0].name]);
|
|
1710
|
+
}
|
|
1711
|
+
|
|
1712
|
+
// Create a vertical split with one pane per script
|
|
1713
|
+
const panes = runningScripts.map(s => {
|
|
1714
|
+
const pane = createPane([s.name]);
|
|
1715
|
+
pane.name = s.displayName;
|
|
1716
|
+
return pane;
|
|
1717
|
+
});
|
|
1718
|
+
|
|
1719
|
+
return createSplit('vertical', panes);
|
|
1720
|
+
}
|
|
1721
|
+
|
|
1722
|
+
// Toggle between column view (one pane per script) and the normal saved layout
|
|
1723
|
+
toggleColumnView() {
|
|
1724
|
+
if (this.isColumnView) {
|
|
1725
|
+
// Restore the saved pane tree
|
|
1726
|
+
if (this.savedPaneRoot) {
|
|
1727
|
+
this.paneRoot = this.savedPaneRoot;
|
|
1728
|
+
this.savedPaneRoot = null;
|
|
1729
|
+
} else {
|
|
1730
|
+
this.paneRoot = createPane([]);
|
|
1731
|
+
}
|
|
1732
|
+
this.isColumnView = false;
|
|
1733
|
+
} else {
|
|
1734
|
+
// Save current pane tree and switch to column view
|
|
1735
|
+
this.savedPaneRoot = this.paneRoot;
|
|
1736
|
+
this.paneRoot = this.generateColumnViewPaneTree();
|
|
1737
|
+
this.isColumnView = true;
|
|
1738
|
+
}
|
|
1739
|
+
|
|
1740
|
+
// Focus the first pane in the new tree
|
|
1741
|
+
const allPanes = getAllPaneIds(this.paneRoot);
|
|
1742
|
+
if (allPanes.length > 0) {
|
|
1743
|
+
this.focusedPaneId = allPanes[0];
|
|
1744
|
+
}
|
|
1745
|
+
|
|
1746
|
+
this.buildRunningUI();
|
|
1747
|
+
}
|
|
1748
|
+
|
|
1749
|
+
// Exit column view mode without restoring saved layout (e.g. user manually split/closed a pane)
|
|
1750
|
+
exitColumnViewMode() {
|
|
1751
|
+
if (this.isColumnView) {
|
|
1752
|
+
this.isColumnView = false;
|
|
1753
|
+
this.savedPaneRoot = null;
|
|
1754
|
+
}
|
|
1755
|
+
}
|
|
1756
|
+
|
|
1677
1757
|
// Move the currently selected process to the focused pane
|
|
1678
1758
|
moveProcessToCurrentPane() {
|
|
1679
1759
|
const scriptName = this.scripts[this.selectedIndex]?.name;
|
|
@@ -1760,6 +1840,8 @@ class ProcessManager {
|
|
|
1760
1840
|
|
|
1761
1841
|
// Save the current pane layout to config (debounced to avoid excessive disk writes)
|
|
1762
1842
|
savePaneLayout() {
|
|
1843
|
+
// Don't save the auto-generated column view layout - it's transient
|
|
1844
|
+
if (this.isColumnView) return;
|
|
1763
1845
|
this.config.paneLayout = serializePaneTree(this.paneRoot);
|
|
1764
1846
|
debouncedSaveConfig(this.config);
|
|
1765
1847
|
}
|
|
@@ -2592,6 +2674,22 @@ class ProcessManager {
|
|
|
2592
2674
|
this.refreshGitStatus();
|
|
2593
2675
|
this.buildRunningUI();
|
|
2594
2676
|
}, 10);
|
|
2677
|
+
} else if (keyName === 'l') {
|
|
2678
|
+
// Pull
|
|
2679
|
+
this.gitModalPhase = 'pulling';
|
|
2680
|
+
this.gitModalOutput = ['Pulling...'];
|
|
2681
|
+
this.buildRunningUI();
|
|
2682
|
+
setTimeout(() => {
|
|
2683
|
+
const result = gitPull();
|
|
2684
|
+
if (result.success) {
|
|
2685
|
+
this.gitModalOutput = [result.output];
|
|
2686
|
+
} else {
|
|
2687
|
+
this.gitModalOutput = [`Pull failed: ${result.error}`];
|
|
2688
|
+
}
|
|
2689
|
+
this.gitModalPhase = 'result';
|
|
2690
|
+
this.refreshGitStatus();
|
|
2691
|
+
this.buildRunningUI();
|
|
2692
|
+
}, 10);
|
|
2595
2693
|
} else if (keyName === 'r') {
|
|
2596
2694
|
// Refresh status
|
|
2597
2695
|
this.refreshGitStatus();
|
|
@@ -2670,6 +2768,22 @@ class ProcessManager {
|
|
|
2670
2768
|
this.refreshGitStatus();
|
|
2671
2769
|
this.buildRunningUI();
|
|
2672
2770
|
}, 10);
|
|
2771
|
+
} else if (keyName === 'l') {
|
|
2772
|
+
// Allow pulling from result phase
|
|
2773
|
+
this.gitModalPhase = 'pulling';
|
|
2774
|
+
this.gitModalOutput = ['Pulling...'];
|
|
2775
|
+
this.buildRunningUI();
|
|
2776
|
+
setTimeout(() => {
|
|
2777
|
+
const result = gitPull();
|
|
2778
|
+
if (result.success) {
|
|
2779
|
+
this.gitModalOutput = [result.output];
|
|
2780
|
+
} else {
|
|
2781
|
+
this.gitModalOutput = [`Pull failed: ${result.error}`];
|
|
2782
|
+
}
|
|
2783
|
+
this.gitModalPhase = 'result';
|
|
2784
|
+
this.refreshGitStatus();
|
|
2785
|
+
this.buildRunningUI();
|
|
2786
|
+
}, 10);
|
|
2673
2787
|
} else {
|
|
2674
2788
|
this.gitModalPhase = 'status';
|
|
2675
2789
|
this.refreshGitStatus();
|
|
@@ -3762,6 +3876,7 @@ class ProcessManager {
|
|
|
3762
3876
|
let titleIcon = '';
|
|
3763
3877
|
if (this.gitModalPhase === 'committing') titleIcon = '...';
|
|
3764
3878
|
else if (this.gitModalPhase === 'pushing') titleIcon = '...';
|
|
3879
|
+
else if (this.gitModalPhase === 'pulling') titleIcon = '...';
|
|
3765
3880
|
else titleIcon = '';
|
|
3766
3881
|
const title = ` Git: ${branch} ${titleIcon}`;
|
|
3767
3882
|
|
|
@@ -3851,9 +3966,9 @@ class ProcessManager {
|
|
|
3851
3966
|
content: t`${fg(COLORS.textDim)('All changes will be staged and committed.')}`,
|
|
3852
3967
|
});
|
|
3853
3968
|
overlay.add(commitHint);
|
|
3854
|
-
} else if (this.gitModalPhase === 'committing' || this.gitModalPhase === 'pushing') {
|
|
3969
|
+
} else if (this.gitModalPhase === 'committing' || this.gitModalPhase === 'pushing' || this.gitModalPhase === 'pulling') {
|
|
3855
3970
|
// Show busy indicator
|
|
3856
|
-
const busyText = this.gitModalPhase === 'committing' ? 'Committing...' : 'Pushing...';
|
|
3971
|
+
const busyText = this.gitModalPhase === 'committing' ? 'Committing...' : this.gitModalPhase === 'pushing' ? 'Pushing...' : 'Pulling...';
|
|
3857
3972
|
const busyLine = new TextRenderable(this.renderer, {
|
|
3858
3973
|
id: 'git-busy',
|
|
3859
3974
|
content: t`${fg(COLORS.warning)(busyText)}`,
|
|
@@ -4007,7 +4122,7 @@ class ProcessManager {
|
|
|
4007
4122
|
});
|
|
4008
4123
|
hintBar.add(hint);
|
|
4009
4124
|
});
|
|
4010
|
-
} else if (this.gitModalPhase === 'committing' || this.gitModalPhase === 'pushing') {
|
|
4125
|
+
} else if (this.gitModalPhase === 'committing' || this.gitModalPhase === 'pushing' || this.gitModalPhase === 'pulling') {
|
|
4011
4126
|
const hint = new TextRenderable(this.renderer, {
|
|
4012
4127
|
id: 'git-hint-busy',
|
|
4013
4128
|
content: t`${fg(COLORS.warning)('Please wait...')}`,
|
|
@@ -4018,6 +4133,7 @@ class ProcessManager {
|
|
|
4018
4133
|
{ key: 'c', desc: 'commit', color: COLORS.success },
|
|
4019
4134
|
{ key: 'a', desc: 'stage all', color: COLORS.warning },
|
|
4020
4135
|
{ key: 'p', desc: 'push', color: COLORS.cyan },
|
|
4136
|
+
{ key: 'l', desc: 'pull', color: COLORS.cyan },
|
|
4021
4137
|
{ key: 'r', desc: 'refresh', color: COLORS.magenta },
|
|
4022
4138
|
{ key: 'esc', desc: 'close', color: COLORS.error },
|
|
4023
4139
|
];
|
|
@@ -4176,6 +4292,15 @@ class ProcessManager {
|
|
|
4176
4292
|
});
|
|
4177
4293
|
leftSide.add(statusIndicator);
|
|
4178
4294
|
|
|
4295
|
+
// Column view indicator
|
|
4296
|
+
if (this.isColumnView) {
|
|
4297
|
+
const columnIndicator = new TextRenderable(this.renderer, {
|
|
4298
|
+
id: 'column-view-indicator',
|
|
4299
|
+
content: t`${fg(COLORS.cyan)('COLUMNS')}`,
|
|
4300
|
+
});
|
|
4301
|
+
leftSide.add(columnIndicator);
|
|
4302
|
+
}
|
|
4303
|
+
|
|
4179
4304
|
// Git branch indicator
|
|
4180
4305
|
if (IS_GIT_REPO) {
|
|
4181
4306
|
const branch = this.gitBranch || getGitBranch();
|
|
@@ -4286,6 +4411,7 @@ class ProcessManager {
|
|
|
4286
4411
|
// Pane & navigation
|
|
4287
4412
|
[
|
|
4288
4413
|
{ key: '\\', desc: 'panes', color: COLORS.cyan },
|
|
4414
|
+
{ key: '=', desc: this.isColumnView ? 'merged' : 'columns', color: COLORS.cyan },
|
|
4289
4415
|
{ key: '1-9', desc: 'toggle', color: COLORS.success },
|
|
4290
4416
|
],
|
|
4291
4417
|
// Process control
|