startall 0.0.11 → 0.0.12

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 (2) hide show
  1. package/index.js +44 -81
  2. package/package.json +1 -1
package/index.js CHANGED
@@ -328,6 +328,7 @@ class ProcessManager {
328
328
  this.processes = new Map();
329
329
  this.processRefs = new Map();
330
330
  this.outputLines = [];
331
+ this.totalLinesReceived = 0; // Track total lines ever received (never resets)
331
332
  this.filter = '';
332
333
  this.maxOutputLines = 1000;
333
334
  this.maxVisibleLines = null; // Calculated dynamically based on screen height
@@ -734,6 +735,7 @@ class ProcessManager {
734
735
  process: processName,
735
736
  text,
736
737
  timestamp: Date.now(),
738
+ lineNumber: ++this.totalLinesReceived, // Track absolute line number
737
739
  });
738
740
 
739
741
  if (this.outputLines.length > this.maxOutputLines) {
@@ -748,13 +750,10 @@ class ProcessManager {
748
750
  }
749
751
 
750
752
  scheduleRender() {
751
- // Throttle renders to ~60fps to reduce CPU usage
752
- if (this.renderScheduled) return;
753
- this.renderScheduled = true;
754
- setTimeout(() => {
755
- this.renderScheduled = false;
753
+ // Update the DOM - OpenTUI's render loop will pick up changes automatically
754
+ if (!this.destroyed) {
756
755
  this.render();
757
- }, 16);
756
+ }
758
757
  }
759
758
 
760
759
  stopProcess(scriptName) {
@@ -1815,87 +1814,51 @@ class ProcessManager {
1815
1814
  }
1816
1815
 
1817
1816
  updateRunningUI() {
1818
- // Update existing panes instead of rebuilding everything
1817
+ // Update existing panes incrementally, or rebuild if needed
1819
1818
  if (this.paneScrollBoxes.size > 0) {
1820
- // Update each pane's content
1819
+ // Incremental update - just append new lines to existing panes
1820
+ let hasNewContent = false;
1821
+
1821
1822
  for (const [paneId, scrollBox] of this.paneScrollBoxes.entries()) {
1822
1823
  const pane = findPaneById(this.paneRoot, paneId);
1823
1824
  if (pane && scrollBox && scrollBox.content) {
1824
- // Check if filter state changed or if paused (requires rebuild)
1825
- const currentFilterState = JSON.stringify({
1826
- filter: pane.filter || '',
1827
- hidden: pane.hidden || [],
1828
- processes: pane.processes || [],
1829
- colorFilter: pane.colorFilter || null,
1830
- });
1831
- const previousFilterState = this.paneFilterState.get(paneId);
1832
- const filterChanged = currentFilterState !== previousFilterState;
1833
- const needsRebuild = filterChanged || this.isPaused;
1825
+ const lines = this.getOutputLinesForPane(pane);
1826
+ const lastRenderedLineNumber = this.paneLineCount.get(paneId) || 0;
1834
1827
 
1835
- if (needsRebuild) {
1836
- // Filter changed - need to rebuild all content
1837
- this.paneFilterState.set(paneId, currentFilterState);
1828
+ // Find lines that haven't been rendered yet (based on absolute line number)
1829
+ const newLines = lines.filter(line => line.lineNumber > lastRenderedLineNumber);
1830
+
1831
+ if (newLines.length > 0) {
1832
+ hasNewContent = true;
1838
1833
 
1839
- // Remove all children
1840
- if (scrollBox.content.children) {
1841
- while (scrollBox.content.children.length > 0) {
1842
- const child = scrollBox.content.children[0];
1843
- if (child && child.id) {
1844
- scrollBox.content.remove(child.id);
1845
- } else {
1846
- break;
1847
- }
1834
+ for (let i = 0; i < newLines.length; i++) {
1835
+ const line = newLines[i];
1836
+ const processColor = this.processColors.get(line.process) || COLORS.text;
1837
+ const trimmedText = line.text.trim();
1838
+ const lineNumber = String(line.lineNumber).padStart(4, ' ');
1839
+
1840
+ const outputLine = new TextRenderable(this.renderer, {
1841
+ id: `output-${pane.id}-${line.lineNumber}`,
1842
+ content: t`${fg(COLORS.textDim)(lineNumber)} ${fg(processColor)(`[${line.process}]`)} ${trimmedText}`,
1843
+ bg: '#000000',
1844
+ });
1845
+
1846
+ scrollBox.content.add(outputLine);
1847
+
1848
+ // Remove oldest line if we exceed maxOutputLines to maintain rolling window
1849
+ if (scrollBox.content.children && scrollBox.content.children.length > this.maxOutputLines) {
1850
+ const oldestChild = scrollBox.content.children[0];
1851
+ scrollBox.content.remove(oldestChild);
1848
1852
  }
1849
1853
  }
1850
1854
 
1851
- // Rebuild all content
1852
- const height = scrollBox.height || this.renderer.height - 6;
1853
- this.buildPaneOutput(pane, scrollBox.content, height);
1854
-
1855
- // Update line count after rebuild
1856
- const lines = this.getOutputLinesForPane(pane);
1857
- this.paneLineCount.set(paneId, lines.length);
1855
+ // Update to track the last absolute line number we rendered
1856
+ this.paneLineCount.set(paneId, newLines[newLines.length - 1].lineNumber);
1858
1857
 
1859
- // Auto-scroll to bottom after filter change
1860
- if (!this.isPaused) {
1858
+ // Auto-scroll to bottom if not paused
1859
+ if (!this.isPaused && scrollBox.scrollTo) {
1861
1860
  scrollBox.scrollTo({ x: 0, y: Number.MAX_SAFE_INTEGER });
1862
1861
  }
1863
- } else {
1864
- // No filter change - just append new lines
1865
- const lines = this.getOutputLinesForPane(pane);
1866
- const lastRenderedCount = this.paneLineCount.get(paneId) || 0;
1867
-
1868
- if (lines.length > lastRenderedCount) {
1869
- const newLines = lines.slice(lastRenderedCount);
1870
-
1871
- for (let i = 0; i < newLines.length; i++) {
1872
- const line = newLines[i];
1873
- const lineIndex = lastRenderedCount + i;
1874
- const processColor = this.processColors.get(line.process) || COLORS.text;
1875
- const trimmedText = line.text.trim();
1876
-
1877
- const outputLine = new TextRenderable(this.renderer, {
1878
- id: `output-${pane.id}-${lineIndex}`,
1879
- content: t`${fg(processColor)(`[${line.process}]`)} ${trimmedText}`,
1880
- bg: '#000000',
1881
- });
1882
-
1883
- scrollBox.content.add(outputLine);
1884
- }
1885
-
1886
- // Update line count
1887
- this.paneLineCount.set(paneId, lines.length);
1888
-
1889
- // Auto-scroll to bottom if not paused
1890
- if (!this.isPaused) {
1891
- scrollBox.scrollTo({ x: 0, y: Number.MAX_SAFE_INTEGER });
1892
- }
1893
- }
1894
- }
1895
-
1896
- // Update scrollbar visibility based on pause state
1897
- if (scrollBox.verticalScrollBar) {
1898
- scrollBox.verticalScrollBar.width = this.isPaused ? 1 : 0;
1899
1862
  }
1900
1863
  }
1901
1864
  }
@@ -1920,9 +1883,10 @@ class ProcessManager {
1920
1883
 
1921
1884
  // Trim whitespace and let text wrap naturally - ScrollBox will handle overflow
1922
1885
  const trimmedText = line.text.trim();
1886
+ const lineNumber = String(i + 1).padStart(4, ' ');
1923
1887
  const outputLine = new TextRenderable(this.renderer, {
1924
1888
  id: `output-${pane.id}-${i}`,
1925
- content: t`${fg(processColor)(`[${line.process}]`)} ${trimmedText}`,
1889
+ content: t`${fg(COLORS.textDim)(lineNumber)} ${fg(processColor)(`[${line.process}]`)} ${trimmedText}`,
1926
1890
  bg: '#000000', // Black background for pane content
1927
1891
  });
1928
1892
 
@@ -2012,10 +1976,8 @@ class ProcessManager {
2012
1976
 
2013
1977
  this.buildPaneOutput(pane, outputBox.content, height);
2014
1978
 
2015
- // Restore or set scroll position
2016
- setTimeout(() => {
2017
- if (!outputBox || !outputBox.scrollTo) return;
2018
-
1979
+ // Restore or set scroll position immediately
1980
+ if (outputBox && outputBox.scrollTo) {
2019
1981
  if (this.isPaused && this.paneScrollPositions.has(pane.id)) {
2020
1982
  // Restore saved scroll position when paused
2021
1983
  const savedPos = this.paneScrollPositions.get(pane.id);
@@ -2024,7 +1986,7 @@ class ProcessManager {
2024
1986
  // Auto-scroll to bottom when not paused
2025
1987
  outputBox.scrollTo({ x: 0, y: Number.MAX_SAFE_INTEGER });
2026
1988
  }
2027
- }, 0);
1989
+ }
2028
1990
 
2029
1991
  paneContainer.add(outputBox);
2030
1992
  return paneContainer;
@@ -2352,6 +2314,7 @@ async function main() {
2352
2314
  }
2353
2315
 
2354
2316
  const renderer = await createCliRenderer();
2317
+ renderer.start(); // Start the automatic render loop
2355
2318
  const manager = new ProcessManager(renderer, scripts);
2356
2319
 
2357
2320
  // Handle cleanup on exit
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "startall",
3
- "version": "0.0.11",
3
+ "version": "0.0.12",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "bin": {