spawn-term 3.1.5 → 3.2.1
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/cjs/components/App.js +136 -6
- package/dist/cjs/components/App.js.map +1 -1
- package/dist/cjs/components/ExpandedOutput.js +5 -2
- package/dist/cjs/components/ExpandedOutput.js.map +1 -1
- package/dist/cjs/components/FullscreenOverlay.js +88 -0
- package/dist/cjs/components/FullscreenOverlay.js.map +1 -0
- package/dist/cjs/src/components/FullscreenOverlay.d.ts +9 -0
- package/dist/cjs/src/state/processStore.d.ts +19 -0
- package/dist/cjs/state/processStore.js +119 -2
- package/dist/cjs/state/processStore.js.map +1 -1
- package/dist/esm/components/App.js +134 -6
- package/dist/esm/components/App.js.map +1 -1
- package/dist/esm/components/ExpandedOutput.js +5 -2
- package/dist/esm/components/ExpandedOutput.js.map +1 -1
- package/dist/esm/components/FullscreenOverlay.js +74 -0
- package/dist/esm/components/FullscreenOverlay.js.map +1 -0
- package/dist/esm/src/components/FullscreenOverlay.d.ts +9 -0
- package/dist/esm/src/state/processStore.d.ts +19 -0
- package/dist/esm/state/processStore.js +103 -2
- package/dist/esm/state/processStore.js.map +1 -1
- package/package.json +1 -1
|
@@ -94,6 +94,12 @@ function _unsupported_iterable_to_array(o, minLen) {
|
|
|
94
94
|
if (n === "Map" || n === "Set") return Array.from(n);
|
|
95
95
|
if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array(o, minLen);
|
|
96
96
|
}
|
|
97
|
+
var FILTER_CYCLE = [
|
|
98
|
+
'all',
|
|
99
|
+
'running',
|
|
100
|
+
'finished',
|
|
101
|
+
'failed'
|
|
102
|
+
];
|
|
97
103
|
var ProcessStore = /*#__PURE__*/ function() {
|
|
98
104
|
"use strict";
|
|
99
105
|
function ProcessStore() {
|
|
@@ -107,6 +113,10 @@ var ProcessStore = /*#__PURE__*/ function() {
|
|
|
107
113
|
this.mode = 'normal';
|
|
108
114
|
this.expandedId = null;
|
|
109
115
|
this.errorFooterExpanded = false; // For non-interactive error footer
|
|
116
|
+
this.filterMode = 'all';
|
|
117
|
+
this.searchTerm = '';
|
|
118
|
+
this.isSearching = false;
|
|
119
|
+
this.isFullscreen = false;
|
|
110
120
|
this.showStatusBar = false;
|
|
111
121
|
this.isInteractive = false;
|
|
112
122
|
// === INFRASTRUCTURE ===
|
|
@@ -194,6 +204,48 @@ var ProcessStore = /*#__PURE__*/ function() {
|
|
|
194
204
|
this.getBufferVersion = function() {
|
|
195
205
|
return _this.bufferVersion;
|
|
196
206
|
};
|
|
207
|
+
this.getFilterMode = function() {
|
|
208
|
+
return _this.filterMode;
|
|
209
|
+
};
|
|
210
|
+
this.getSearchTerm = function() {
|
|
211
|
+
return _this.searchTerm;
|
|
212
|
+
};
|
|
213
|
+
this.getIsSearching = function() {
|
|
214
|
+
return _this.isSearching;
|
|
215
|
+
};
|
|
216
|
+
this.getIsFullscreen = function() {
|
|
217
|
+
return _this.isFullscreen;
|
|
218
|
+
};
|
|
219
|
+
// Get processes filtered by current filter mode and search term
|
|
220
|
+
this.getFilteredProcesses = function() {
|
|
221
|
+
var filtered = _this.processes;
|
|
222
|
+
// Apply filter mode
|
|
223
|
+
switch(_this.filterMode){
|
|
224
|
+
case 'running':
|
|
225
|
+
filtered = filtered.filter(function(p) {
|
|
226
|
+
return p.state === 'running';
|
|
227
|
+
});
|
|
228
|
+
break;
|
|
229
|
+
case 'finished':
|
|
230
|
+
filtered = filtered.filter(function(p) {
|
|
231
|
+
return p.state !== 'running';
|
|
232
|
+
});
|
|
233
|
+
break;
|
|
234
|
+
case 'failed':
|
|
235
|
+
filtered = filtered.filter(function(p) {
|
|
236
|
+
return p.state === 'error';
|
|
237
|
+
});
|
|
238
|
+
break;
|
|
239
|
+
}
|
|
240
|
+
// Apply search term
|
|
241
|
+
if (_this.searchTerm) {
|
|
242
|
+
var term = _this.searchTerm.toLowerCase();
|
|
243
|
+
filtered = filtered.filter(function(p) {
|
|
244
|
+
return p.title.toLowerCase().includes(term) || p.group && p.group.toLowerCase().includes(term);
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
return filtered;
|
|
248
|
+
};
|
|
197
249
|
// Get scroll offset for expanded process (or 0 if none)
|
|
198
250
|
this.getScrollOffset = function() {
|
|
199
251
|
var _process_scrollNav;
|
|
@@ -229,9 +281,10 @@ var ProcessStore = /*#__PURE__*/ function() {
|
|
|
229
281
|
var _options_interactive;
|
|
230
282
|
this.isInteractive = (_options_interactive = options.interactive) !== null && _options_interactive !== void 0 ? _options_interactive : false;
|
|
231
283
|
// Create list navigator with wrap-around behavior
|
|
284
|
+
// Uses filtered processes count so selection works correctly with filters
|
|
232
285
|
this.listNav = (0, _Navigatorts.createNavigator)({
|
|
233
286
|
getLength: function() {
|
|
234
|
-
return _this.
|
|
287
|
+
return _this.getFilteredProcesses().length;
|
|
235
288
|
},
|
|
236
289
|
wrap: true,
|
|
237
290
|
onMove: function() {
|
|
@@ -337,7 +390,67 @@ var ProcessStore = /*#__PURE__*/ function() {
|
|
|
337
390
|
this.notify();
|
|
338
391
|
};
|
|
339
392
|
_proto.getSelectedProcess = function getSelectedProcess() {
|
|
340
|
-
return this.
|
|
393
|
+
return this.getFilteredProcesses()[this.listNav.position];
|
|
394
|
+
};
|
|
395
|
+
// Filter mode cycling (left/right arrows)
|
|
396
|
+
_proto.cycleFilterNext = function cycleFilterNext() {
|
|
397
|
+
var currentIndex = FILTER_CYCLE.indexOf(this.filterMode);
|
|
398
|
+
this.filterMode = FILTER_CYCLE[(currentIndex + 1) % FILTER_CYCLE.length];
|
|
399
|
+
// Reset selection when filter changes
|
|
400
|
+
this.listNav.toStart();
|
|
401
|
+
// Collapse any expanded process when filter changes
|
|
402
|
+
this.expandedId = null;
|
|
403
|
+
this.notify();
|
|
404
|
+
};
|
|
405
|
+
_proto.cycleFilterPrev = function cycleFilterPrev() {
|
|
406
|
+
var currentIndex = FILTER_CYCLE.indexOf(this.filterMode);
|
|
407
|
+
this.filterMode = FILTER_CYCLE[(currentIndex - 1 + FILTER_CYCLE.length) % FILTER_CYCLE.length];
|
|
408
|
+
// Reset selection when filter changes
|
|
409
|
+
this.listNav.toStart();
|
|
410
|
+
// Collapse any expanded process when filter changes
|
|
411
|
+
this.expandedId = null;
|
|
412
|
+
this.notify();
|
|
413
|
+
};
|
|
414
|
+
// Search mode
|
|
415
|
+
_proto.startSearch = function startSearch() {
|
|
416
|
+
this.isSearching = true;
|
|
417
|
+
this.searchTerm = '';
|
|
418
|
+
this.notify();
|
|
419
|
+
};
|
|
420
|
+
_proto.updateSearchTerm = function updateSearchTerm(term) {
|
|
421
|
+
this.searchTerm = term;
|
|
422
|
+
// Reset selection when search changes
|
|
423
|
+
this.listNav.toStart();
|
|
424
|
+
this.notify();
|
|
425
|
+
};
|
|
426
|
+
_proto.cancelSearch = function cancelSearch() {
|
|
427
|
+
this.isSearching = false;
|
|
428
|
+
this.searchTerm = '';
|
|
429
|
+
// Reset selection
|
|
430
|
+
this.listNav.toStart();
|
|
431
|
+
this.notify();
|
|
432
|
+
};
|
|
433
|
+
_proto.confirmSearch = function confirmSearch() {
|
|
434
|
+
this.isSearching = false;
|
|
435
|
+
// Keep searchTerm applied, reset selection to first match
|
|
436
|
+
this.listNav.toStart();
|
|
437
|
+
this.notify();
|
|
438
|
+
};
|
|
439
|
+
_proto.clearSearch = function clearSearch() {
|
|
440
|
+
this.searchTerm = '';
|
|
441
|
+
this.listNav.toStart();
|
|
442
|
+
this.notify();
|
|
443
|
+
};
|
|
444
|
+
// Fullscreen mode (alternate screen buffer)
|
|
445
|
+
_proto.enterFullscreen = function enterFullscreen() {
|
|
446
|
+
if (this.expandedId) {
|
|
447
|
+
this.isFullscreen = true;
|
|
448
|
+
this.notify();
|
|
449
|
+
}
|
|
450
|
+
};
|
|
451
|
+
_proto.exitFullscreen = function exitFullscreen() {
|
|
452
|
+
this.isFullscreen = false;
|
|
453
|
+
this.notify();
|
|
341
454
|
};
|
|
342
455
|
// Error footer methods (for non-interactive mode)
|
|
343
456
|
_proto.toggleErrorFooter = function toggleErrorFooter() {
|
|
@@ -513,6 +626,10 @@ var ProcessStore = /*#__PURE__*/ function() {
|
|
|
513
626
|
this.listNav.reset();
|
|
514
627
|
this.expandedId = null;
|
|
515
628
|
this.errorFooterExpanded = false;
|
|
629
|
+
this.filterMode = 'all';
|
|
630
|
+
this.searchTerm = '';
|
|
631
|
+
this.isSearching = false;
|
|
632
|
+
this.isFullscreen = false;
|
|
516
633
|
this.header = undefined;
|
|
517
634
|
};
|
|
518
635
|
// === INFRASTRUCTURE ===
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/node/spawn-term/src/state/processStore.ts"],"sourcesContent":["import { arrayFind } from '../compat.ts';\nimport { DEFAULT_COLUMN_WIDTH } from '../constants.ts';\nimport type { ChildProcess, Line, SessionOptions } from '../types.ts';\nimport { LineType } from '../types.ts';\nimport { createNavigator, type Navigator } from './Navigator.ts';\n\ntype Listener = () => void;\ntype Mode = 'normal' | 'interactive';\n\nexport class ProcessStore {\n // === DATA: Process collection ===\n private processes: ChildProcess[] = [];\n private completedIds: string[] = []; // Track completion order\n\n // === NAVIGATION: List cursor ===\n private listNav: Navigator;\n\n // === VIEW STATE ===\n private mode: Mode = 'normal';\n private expandedId: string | null = null;\n private errorFooterExpanded = false; // For non-interactive error footer\n\n // === SESSION CONFIG (immutable after construction) ===\n private header: string | undefined;\n private showStatusBar = false;\n private isInteractive = false;\n\n // === INFRASTRUCTURE ===\n private listeners = new Set<Listener>();\n private shouldExit = false;\n private exitCallback: (() => void) | null = null;\n private bufferVersion = 0; // Increments on every notify() to trigger re-renders\n\n constructor(options: SessionOptions = {}) {\n this.header = options.header;\n this.showStatusBar = options.showStatusBar ?? false;\n this.isInteractive = options.interactive ?? false;\n\n // Create list navigator with wrap-around behavior\n this.listNav = createNavigator({\n getLength: () => this.processes.length,\n wrap: true,\n onMove: () => this.notify(),\n });\n }\n\n // === SUBSCRIPTION API (useSyncExternalStore) ===\n\n subscribe = (listener: Listener): (() => void) => {\n this.listeners.add(listener);\n return () => this.listeners.delete(listener);\n };\n\n getSnapshot = (): ChildProcess[] => this.processes;\n\n // === DATA: Queries ===\n\n getRunningProcesses = (): ChildProcess[] => {\n return this.processes.filter((p) => p.state === 'running');\n };\n\n getCompletedProcesses = (): ChildProcess[] => {\n // Return in completion order\n return this.completedIds.map((id) => arrayFind(this.processes, (p) => p.id === id)).filter((p): p is ChildProcess => p !== undefined);\n };\n\n getFailedProcesses = (): ChildProcess[] => {\n return this.processes.filter((p) => p.state === 'error');\n };\n\n // Counts\n getRunningCount = (): number => this.processes.filter((p) => p.state === 'running').length;\n getMaxGroupLength = (): number => {\n if (this.processes.length === 0) return DEFAULT_COLUMN_WIDTH;\n return Math.max(...this.processes.map((p) => (p.group || p.title).length));\n };\n getDoneCount = (): number => this.processes.filter((p) => p.state !== 'running').length;\n getErrorCount = (): number => this.processes.filter((p) => p.state === 'error').length;\n getErrorLineCount = (): number => {\n return this.processes.filter((p) => p.state === 'error').reduce((total, p) => total + this.getProcessLineCount(p.id), 0);\n };\n\n getErrorLines(): Array<{ processName: string; lines: Line[] }> {\n return this.getFailedProcesses().map((p) => ({\n processName: p.group || p.title,\n lines: this.getProcessLines(p.id),\n }));\n }\n\n // === DATA: Mutations ===\n\n addProcess(process: ChildProcess): void {\n // Create scroll navigator for this process\n const processWithNav: ChildProcess = {\n ...process,\n scrollNav: createNavigator({\n getLength: () => this.getProcessLineCount(processWithNav.id),\n wrap: false,\n onMove: () => this.notify(),\n }),\n };\n this.processes = [...this.processes, processWithNav];\n this.notify();\n }\n\n updateProcess(id: string, update: Partial<ChildProcess>): void {\n const oldProcess = arrayFind(this.processes, (p) => p.id === id);\n const wasRunning = oldProcess?.state === 'running';\n const isNowComplete = update.state && update.state !== 'running';\n\n this.processes = this.processes.map((p) => (p.id === id ? { ...p, ...update } : p));\n\n // Track completion order\n if (wasRunning && isNowComplete && !this.completedIds.includes(id)) {\n this.completedIds = [...this.completedIds, id];\n }\n\n // Auto-expand error footer when all complete with errors (non-interactive only)\n if (!this.isInteractive && this.isAllComplete() && this.getErrorCount() > 0) {\n this.errorFooterExpanded = true;\n }\n\n this.notify();\n }\n\n appendLines(id: string, newLines: Line[]): void {\n const process = arrayFind(this.processes, (p) => p.id === id);\n if (process) {\n this.updateProcess(id, { lines: process.lines.concat(newLines) });\n }\n }\n\n getProcess(id: string): ChildProcess | undefined {\n return arrayFind(this.processes, (p) => p.id === id);\n }\n\n // Get rendered lines from terminal buffer or fallback to lines array\n getProcessLines(id: string): Line[] {\n const process = this.getProcess(id);\n if (!process) return [];\n if (process.terminalBuffer) {\n return process.terminalBuffer.getLines().map((text) => ({\n type: LineType.stdout,\n text,\n }));\n }\n return process.lines;\n }\n\n // Get line count from terminal buffer or lines array\n getProcessLineCount(id: string): number {\n const process = this.getProcess(id);\n if (!process) return 0;\n if (process.terminalBuffer) {\n return process.terminalBuffer.lineCount;\n }\n return process.lines.length;\n }\n\n // === VIEW STATE: Getters ===\n\n getMode = (): Mode => this.mode;\n getSelectedIndex = (): number => this.listNav.position;\n getExpandedId = (): string | null => this.expandedId;\n getListScrollOffset = (): number => this.listNav.viewportOffset;\n getErrorFooterExpanded = (): boolean => this.errorFooterExpanded;\n getBufferVersion = (): number => this.bufferVersion;\n\n // Get scroll offset for expanded process (or 0 if none)\n getScrollOffset = (): number => {\n if (!this.expandedId) return 0;\n const process = this.getProcess(this.expandedId);\n return process?.scrollNav?.position ?? 0;\n };\n\n // Session-level getters (set at session creation, immutable)\n getHeader = (): string | undefined => this.header;\n getShowStatusBar = (): boolean => this.showStatusBar;\n getIsInteractive = (): boolean => this.isInteractive;\n isAllComplete = (): boolean => this.processes.length > 0 && this.processes.every((p) => p.state !== 'running');\n\n // === VIEW STATE: Mutations ===\n\n setMode(mode: Mode): void {\n this.mode = mode;\n if (mode === 'interactive') {\n this.listNav.setPosition(0);\n }\n this.notify();\n }\n\n getSelectedProcess(): ChildProcess | undefined {\n return this.processes[this.listNav.position];\n }\n\n // Error footer methods (for non-interactive mode)\n toggleErrorFooter(): void {\n this.errorFooterExpanded = !this.errorFooterExpanded;\n this.notify();\n }\n\n expandErrorFooter(): void {\n if (!this.errorFooterExpanded) {\n this.errorFooterExpanded = true;\n this.notify();\n }\n }\n\n // === NAVIGATION: List (delegates to listNav) ===\n\n selectNext(visibleCount?: number): void {\n this.listNav.down();\n if (visibleCount) {\n this.listNav.ensureVisible(visibleCount);\n }\n }\n\n selectPrev(visibleCount?: number): void {\n this.listNav.up();\n if (visibleCount) {\n this.listNav.ensureVisible(visibleCount);\n }\n }\n\n selectPageDown(pageSize: number, visibleCount?: number): void {\n this.listNav.pageDown(pageSize, visibleCount);\n }\n\n selectPageUp(pageSize: number, visibleCount?: number): void {\n this.listNav.pageUp(pageSize, visibleCount);\n }\n\n selectFirst(visibleCount?: number): void {\n this.listNav.toStart();\n if (visibleCount) {\n this.listNav.ensureVisible(visibleCount);\n }\n }\n\n selectLast(visibleCount?: number): void {\n this.listNav.toEnd();\n if (visibleCount) {\n this.listNav.ensureVisible(visibleCount);\n }\n }\n\n clampListViewport(visibleCount: number): void {\n const changed = this.listNav.clampViewport(visibleCount);\n if (changed) {\n this.notify();\n }\n }\n\n // === NAVIGATION: Expanded content (delegates to process.scrollNav) ===\n\n private getExpandedNav(): { nav: Navigator; id: string } | undefined {\n if (!this.expandedId) return undefined;\n const nav = this.getProcess(this.expandedId)?.scrollNav;\n if (!nav) return undefined;\n return { nav, id: this.expandedId };\n }\n\n scrollDown(maxVisible: number): void {\n const expanded = this.getExpandedNav();\n if (!expanded) return;\n\n const lineCount = this.getProcessLineCount(expanded.id);\n const maxOffset = Math.max(0, lineCount - maxVisible);\n\n // Only scroll if not at bottom\n if (expanded.nav.position < maxOffset) {\n expanded.nav.down();\n }\n }\n\n scrollUp(): void {\n const expanded = this.getExpandedNav();\n if (!expanded) return;\n\n if (expanded.nav.position > 0) {\n expanded.nav.up();\n }\n }\n\n scrollPageDown(pageSize: number): void {\n const expanded = this.getExpandedNav();\n if (!expanded) return;\n\n const lineCount = this.getProcessLineCount(expanded.id);\n const maxOffset = Math.max(0, lineCount - pageSize);\n\n // Clamp to max offset\n const newPosition = Math.min(expanded.nav.position + pageSize, maxOffset);\n expanded.nav.setPosition(newPosition);\n this.notify();\n }\n\n scrollPageUp(pageSize: number): void {\n const expanded = this.getExpandedNav();\n if (!expanded) return;\n\n const newPosition = Math.max(0, expanded.nav.position - pageSize);\n expanded.nav.setPosition(newPosition);\n this.notify();\n }\n\n scrollToTop(): void {\n const expanded = this.getExpandedNav();\n if (!expanded) return;\n expanded.nav.toStart();\n }\n\n scrollToBottom(maxVisible: number): void {\n const expanded = this.getExpandedNav();\n if (!expanded) return;\n\n const lineCount = this.getProcessLineCount(expanded.id);\n const newPosition = Math.max(0, lineCount - maxVisible);\n expanded.nav.setPosition(newPosition);\n this.notify();\n }\n\n // === EXPANSION ===\n\n toggleExpand(visibleCountWhenExpanded?: number, visibleCountWhenCollapsed?: number): void {\n const selected = this.getSelectedProcess();\n if (!selected) return;\n\n if (this.expandedId === selected.id) {\n // Collapse (keep scroll position for later)\n this.expandedId = null;\n // Adjust viewport to avoid empty space at bottom\n if (visibleCountWhenCollapsed) {\n this.listNav.clampViewport(visibleCountWhenCollapsed);\n }\n } else {\n // Expand (scroll position is preserved in process.scrollNav)\n this.expandedId = selected.id;\n // Adjust list scroll to keep expanded process visible\n if (visibleCountWhenExpanded) {\n this.listNav.ensureVisible(visibleCountWhenExpanded);\n }\n }\n this.notify();\n }\n\n collapse(visibleCountWhenCollapsed?: number): void {\n // Collapse but keep scroll position in process\n this.expandedId = null;\n // Adjust viewport to avoid empty space at bottom\n if (visibleCountWhenCollapsed) {\n this.listNav.clampViewport(visibleCountWhenCollapsed);\n }\n this.notify();\n }\n\n // === EXIT ===\n\n signalExit(callback: () => void): void {\n this.shouldExit = true;\n this.exitCallback = callback;\n this.notify();\n }\n\n getShouldExit = (): boolean => this.shouldExit;\n getExitCallback = (): (() => void) | null => this.exitCallback;\n\n // === RESET ===\n\n reset(): void {\n // Dispose terminal buffers before clearing\n for (const process of this.processes) {\n process.terminalBuffer?.dispose();\n }\n this.processes = [];\n this.completedIds = [];\n this.shouldExit = false;\n this.exitCallback = null;\n this.mode = 'normal';\n this.listNav.reset();\n this.expandedId = null;\n this.errorFooterExpanded = false;\n this.header = undefined;\n }\n\n // === INFRASTRUCTURE ===\n\n notify(): void {\n this.bufferVersion++;\n this.listeners.forEach((l) => {\n l();\n });\n }\n}\n\n// Note: No global singleton - session creates its own store instance\n"],"names":["ProcessStore","options","processes","completedIds","mode","expandedId","errorFooterExpanded","showStatusBar","isInteractive","listeners","Set","shouldExit","exitCallback","bufferVersion","subscribe","listener","add","delete","getSnapshot","getRunningProcesses","filter","p","state","getCompletedProcesses","map","id","arrayFind","undefined","getFailedProcesses","getRunningCount","length","getMaxGroupLength","Math","DEFAULT_COLUMN_WIDTH","max","group","title","getDoneCount","getErrorCount","getErrorLineCount","reduce","total","getProcessLineCount","getMode","getSelectedIndex","listNav","position","getExpandedId","getListScrollOffset","viewportOffset","getErrorFooterExpanded","getBufferVersion","getScrollOffset","process","getProcess","scrollNav","getHeader","header","getShowStatusBar","getIsInteractive","isAllComplete","every","getShouldExit","getExitCallback","interactive","createNavigator","getLength","wrap","onMove","notify","getErrorLines","processName","lines","getProcessLines","addProcess","processWithNav","updateProcess","update","oldProcess","wasRunning","isNowComplete","includes","appendLines","newLines","concat","terminalBuffer","getLines","text","type","LineType","stdout","lineCount","setMode","setPosition","getSelectedProcess","toggleErrorFooter","expandErrorFooter","selectNext","visibleCount","down","ensureVisible","selectPrev","up","selectPageDown","pageSize","pageDown","selectPageUp","pageUp","selectFirst","toStart","selectLast","toEnd","clampListViewport","changed","clampViewport","getExpandedNav","nav","scrollDown","maxVisible","expanded","maxOffset","scrollUp","scrollPageDown","newPosition","min","scrollPageUp","scrollToTop","scrollToBottom","toggleExpand","visibleCountWhenExpanded","visibleCountWhenCollapsed","selected","collapse","signalExit","callback","reset","dispose","forEach","l"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/node/spawn-term/src/state/processStore.ts"],"sourcesContent":["import { arrayFind } from '../compat.ts';\nimport { DEFAULT_COLUMN_WIDTH } from '../constants.ts';\nimport type { ChildProcess, Line, SessionOptions } from '../types.ts';\nimport { LineType } from '../types.ts';\nimport { createNavigator, type Navigator } from './Navigator.ts';\n\ntype Listener = () => void;\ntype Mode = 'normal' | 'interactive';\ntype FilterMode = 'all' | 'running' | 'finished' | 'failed';\n\nconst FILTER_CYCLE: FilterMode[] = ['all', 'running', 'finished', 'failed'];\n\nexport class ProcessStore {\n // === DATA: Process collection ===\n private processes: ChildProcess[] = [];\n private completedIds: string[] = []; // Track completion order\n\n // === NAVIGATION: List cursor ===\n private listNav: Navigator;\n\n // === VIEW STATE ===\n private mode: Mode = 'normal';\n private expandedId: string | null = null;\n private errorFooterExpanded = false; // For non-interactive error footer\n private filterMode: FilterMode = 'all';\n private searchTerm = '';\n private isSearching = false;\n private isFullscreen = false;\n\n // === SESSION CONFIG (immutable after construction) ===\n private header: string | undefined;\n private showStatusBar = false;\n private isInteractive = false;\n\n // === INFRASTRUCTURE ===\n private listeners = new Set<Listener>();\n private shouldExit = false;\n private exitCallback: (() => void) | null = null;\n private bufferVersion = 0; // Increments on every notify() to trigger re-renders\n\n constructor(options: SessionOptions = {}) {\n this.header = options.header;\n this.showStatusBar = options.showStatusBar ?? false;\n this.isInteractive = options.interactive ?? false;\n\n // Create list navigator with wrap-around behavior\n // Uses filtered processes count so selection works correctly with filters\n this.listNav = createNavigator({\n getLength: () => this.getFilteredProcesses().length,\n wrap: true,\n onMove: () => this.notify(),\n });\n }\n\n // === SUBSCRIPTION API (useSyncExternalStore) ===\n\n subscribe = (listener: Listener): (() => void) => {\n this.listeners.add(listener);\n return () => this.listeners.delete(listener);\n };\n\n getSnapshot = (): ChildProcess[] => this.processes;\n\n // === DATA: Queries ===\n\n getRunningProcesses = (): ChildProcess[] => {\n return this.processes.filter((p) => p.state === 'running');\n };\n\n getCompletedProcesses = (): ChildProcess[] => {\n // Return in completion order\n return this.completedIds.map((id) => arrayFind(this.processes, (p) => p.id === id)).filter((p): p is ChildProcess => p !== undefined);\n };\n\n getFailedProcesses = (): ChildProcess[] => {\n return this.processes.filter((p) => p.state === 'error');\n };\n\n // Counts\n getRunningCount = (): number => this.processes.filter((p) => p.state === 'running').length;\n getMaxGroupLength = (): number => {\n if (this.processes.length === 0) return DEFAULT_COLUMN_WIDTH;\n return Math.max(...this.processes.map((p) => (p.group || p.title).length));\n };\n getDoneCount = (): number => this.processes.filter((p) => p.state !== 'running').length;\n getErrorCount = (): number => this.processes.filter((p) => p.state === 'error').length;\n getErrorLineCount = (): number => {\n return this.processes.filter((p) => p.state === 'error').reduce((total, p) => total + this.getProcessLineCount(p.id), 0);\n };\n\n getErrorLines(): Array<{ processName: string; lines: Line[] }> {\n return this.getFailedProcesses().map((p) => ({\n processName: p.group || p.title,\n lines: this.getProcessLines(p.id),\n }));\n }\n\n // === DATA: Mutations ===\n\n addProcess(process: ChildProcess): void {\n // Create scroll navigator for this process\n const processWithNav: ChildProcess = {\n ...process,\n scrollNav: createNavigator({\n getLength: () => this.getProcessLineCount(processWithNav.id),\n wrap: false,\n onMove: () => this.notify(),\n }),\n };\n this.processes = [...this.processes, processWithNav];\n this.notify();\n }\n\n updateProcess(id: string, update: Partial<ChildProcess>): void {\n const oldProcess = arrayFind(this.processes, (p) => p.id === id);\n const wasRunning = oldProcess?.state === 'running';\n const isNowComplete = update.state && update.state !== 'running';\n\n this.processes = this.processes.map((p) => (p.id === id ? { ...p, ...update } : p));\n\n // Track completion order\n if (wasRunning && isNowComplete && !this.completedIds.includes(id)) {\n this.completedIds = [...this.completedIds, id];\n }\n\n // Auto-expand error footer when all complete with errors (non-interactive only)\n if (!this.isInteractive && this.isAllComplete() && this.getErrorCount() > 0) {\n this.errorFooterExpanded = true;\n }\n\n this.notify();\n }\n\n appendLines(id: string, newLines: Line[]): void {\n const process = arrayFind(this.processes, (p) => p.id === id);\n if (process) {\n this.updateProcess(id, { lines: process.lines.concat(newLines) });\n }\n }\n\n getProcess(id: string): ChildProcess | undefined {\n return arrayFind(this.processes, (p) => p.id === id);\n }\n\n // Get rendered lines from terminal buffer or fallback to lines array\n getProcessLines(id: string): Line[] {\n const process = this.getProcess(id);\n if (!process) return [];\n if (process.terminalBuffer) {\n return process.terminalBuffer.getLines().map((text) => ({\n type: LineType.stdout,\n text,\n }));\n }\n return process.lines;\n }\n\n // Get line count from terminal buffer or lines array\n getProcessLineCount(id: string): number {\n const process = this.getProcess(id);\n if (!process) return 0;\n if (process.terminalBuffer) {\n return process.terminalBuffer.lineCount;\n }\n return process.lines.length;\n }\n\n // === VIEW STATE: Getters ===\n\n getMode = (): Mode => this.mode;\n getSelectedIndex = (): number => this.listNav.position;\n getExpandedId = (): string | null => this.expandedId;\n getListScrollOffset = (): number => this.listNav.viewportOffset;\n getErrorFooterExpanded = (): boolean => this.errorFooterExpanded;\n getBufferVersion = (): number => this.bufferVersion;\n getFilterMode = (): FilterMode => this.filterMode;\n getSearchTerm = (): string => this.searchTerm;\n getIsSearching = (): boolean => this.isSearching;\n getIsFullscreen = (): boolean => this.isFullscreen;\n\n // Get processes filtered by current filter mode and search term\n getFilteredProcesses = (): ChildProcess[] => {\n let filtered = this.processes;\n\n // Apply filter mode\n switch (this.filterMode) {\n case 'running':\n filtered = filtered.filter((p) => p.state === 'running');\n break;\n case 'finished':\n filtered = filtered.filter((p) => p.state !== 'running');\n break;\n case 'failed':\n filtered = filtered.filter((p) => p.state === 'error');\n break;\n }\n\n // Apply search term\n if (this.searchTerm) {\n const term = this.searchTerm.toLowerCase();\n filtered = filtered.filter((p) => p.title.toLowerCase().includes(term) || (p.group && p.group.toLowerCase().includes(term)));\n }\n\n return filtered;\n };\n\n // Get scroll offset for expanded process (or 0 if none)\n getScrollOffset = (): number => {\n if (!this.expandedId) return 0;\n const process = this.getProcess(this.expandedId);\n return process?.scrollNav?.position ?? 0;\n };\n\n // Session-level getters (set at session creation, immutable)\n getHeader = (): string | undefined => this.header;\n getShowStatusBar = (): boolean => this.showStatusBar;\n getIsInteractive = (): boolean => this.isInteractive;\n isAllComplete = (): boolean => this.processes.length > 0 && this.processes.every((p) => p.state !== 'running');\n\n // === VIEW STATE: Mutations ===\n\n setMode(mode: Mode): void {\n this.mode = mode;\n if (mode === 'interactive') {\n this.listNav.setPosition(0);\n }\n this.notify();\n }\n\n getSelectedProcess(): ChildProcess | undefined {\n return this.getFilteredProcesses()[this.listNav.position];\n }\n\n // Filter mode cycling (left/right arrows)\n cycleFilterNext(): void {\n const currentIndex = FILTER_CYCLE.indexOf(this.filterMode);\n this.filterMode = FILTER_CYCLE[(currentIndex + 1) % FILTER_CYCLE.length] as FilterMode;\n // Reset selection when filter changes\n this.listNav.toStart();\n // Collapse any expanded process when filter changes\n this.expandedId = null;\n this.notify();\n }\n\n cycleFilterPrev(): void {\n const currentIndex = FILTER_CYCLE.indexOf(this.filterMode);\n this.filterMode = FILTER_CYCLE[(currentIndex - 1 + FILTER_CYCLE.length) % FILTER_CYCLE.length] as FilterMode;\n // Reset selection when filter changes\n this.listNav.toStart();\n // Collapse any expanded process when filter changes\n this.expandedId = null;\n this.notify();\n }\n\n // Search mode\n startSearch(): void {\n this.isSearching = true;\n this.searchTerm = '';\n this.notify();\n }\n\n updateSearchTerm(term: string): void {\n this.searchTerm = term;\n // Reset selection when search changes\n this.listNav.toStart();\n this.notify();\n }\n\n cancelSearch(): void {\n this.isSearching = false;\n this.searchTerm = '';\n // Reset selection\n this.listNav.toStart();\n this.notify();\n }\n\n confirmSearch(): void {\n this.isSearching = false;\n // Keep searchTerm applied, reset selection to first match\n this.listNav.toStart();\n this.notify();\n }\n\n clearSearch(): void {\n this.searchTerm = '';\n this.listNav.toStart();\n this.notify();\n }\n\n // Fullscreen mode (alternate screen buffer)\n enterFullscreen(): void {\n if (this.expandedId) {\n this.isFullscreen = true;\n this.notify();\n }\n }\n\n exitFullscreen(): void {\n this.isFullscreen = false;\n this.notify();\n }\n\n // Error footer methods (for non-interactive mode)\n toggleErrorFooter(): void {\n this.errorFooterExpanded = !this.errorFooterExpanded;\n this.notify();\n }\n\n expandErrorFooter(): void {\n if (!this.errorFooterExpanded) {\n this.errorFooterExpanded = true;\n this.notify();\n }\n }\n\n // === NAVIGATION: List (delegates to listNav) ===\n\n selectNext(visibleCount?: number): void {\n this.listNav.down();\n if (visibleCount) {\n this.listNav.ensureVisible(visibleCount);\n }\n }\n\n selectPrev(visibleCount?: number): void {\n this.listNav.up();\n if (visibleCount) {\n this.listNav.ensureVisible(visibleCount);\n }\n }\n\n selectPageDown(pageSize: number, visibleCount?: number): void {\n this.listNav.pageDown(pageSize, visibleCount);\n }\n\n selectPageUp(pageSize: number, visibleCount?: number): void {\n this.listNav.pageUp(pageSize, visibleCount);\n }\n\n selectFirst(visibleCount?: number): void {\n this.listNav.toStart();\n if (visibleCount) {\n this.listNav.ensureVisible(visibleCount);\n }\n }\n\n selectLast(visibleCount?: number): void {\n this.listNav.toEnd();\n if (visibleCount) {\n this.listNav.ensureVisible(visibleCount);\n }\n }\n\n clampListViewport(visibleCount: number): void {\n const changed = this.listNav.clampViewport(visibleCount);\n if (changed) {\n this.notify();\n }\n }\n\n // === NAVIGATION: Expanded content (delegates to process.scrollNav) ===\n\n private getExpandedNav(): { nav: Navigator; id: string } | undefined {\n if (!this.expandedId) return undefined;\n const nav = this.getProcess(this.expandedId)?.scrollNav;\n if (!nav) return undefined;\n return { nav, id: this.expandedId };\n }\n\n scrollDown(maxVisible: number): void {\n const expanded = this.getExpandedNav();\n if (!expanded) return;\n\n const lineCount = this.getProcessLineCount(expanded.id);\n const maxOffset = Math.max(0, lineCount - maxVisible);\n\n // Only scroll if not at bottom\n if (expanded.nav.position < maxOffset) {\n expanded.nav.down();\n }\n }\n\n scrollUp(): void {\n const expanded = this.getExpandedNav();\n if (!expanded) return;\n\n if (expanded.nav.position > 0) {\n expanded.nav.up();\n }\n }\n\n scrollPageDown(pageSize: number): void {\n const expanded = this.getExpandedNav();\n if (!expanded) return;\n\n const lineCount = this.getProcessLineCount(expanded.id);\n const maxOffset = Math.max(0, lineCount - pageSize);\n\n // Clamp to max offset\n const newPosition = Math.min(expanded.nav.position + pageSize, maxOffset);\n expanded.nav.setPosition(newPosition);\n this.notify();\n }\n\n scrollPageUp(pageSize: number): void {\n const expanded = this.getExpandedNav();\n if (!expanded) return;\n\n const newPosition = Math.max(0, expanded.nav.position - pageSize);\n expanded.nav.setPosition(newPosition);\n this.notify();\n }\n\n scrollToTop(): void {\n const expanded = this.getExpandedNav();\n if (!expanded) return;\n expanded.nav.toStart();\n }\n\n scrollToBottom(maxVisible: number): void {\n const expanded = this.getExpandedNav();\n if (!expanded) return;\n\n const lineCount = this.getProcessLineCount(expanded.id);\n const newPosition = Math.max(0, lineCount - maxVisible);\n expanded.nav.setPosition(newPosition);\n this.notify();\n }\n\n // === EXPANSION ===\n\n toggleExpand(visibleCountWhenExpanded?: number, visibleCountWhenCollapsed?: number): void {\n const selected = this.getSelectedProcess();\n if (!selected) return;\n\n if (this.expandedId === selected.id) {\n // Collapse (keep scroll position for later)\n this.expandedId = null;\n // Adjust viewport to avoid empty space at bottom\n if (visibleCountWhenCollapsed) {\n this.listNav.clampViewport(visibleCountWhenCollapsed);\n }\n } else {\n // Expand (scroll position is preserved in process.scrollNav)\n this.expandedId = selected.id;\n // Adjust list scroll to keep expanded process visible\n if (visibleCountWhenExpanded) {\n this.listNav.ensureVisible(visibleCountWhenExpanded);\n }\n }\n this.notify();\n }\n\n collapse(visibleCountWhenCollapsed?: number): void {\n // Collapse but keep scroll position in process\n this.expandedId = null;\n // Adjust viewport to avoid empty space at bottom\n if (visibleCountWhenCollapsed) {\n this.listNav.clampViewport(visibleCountWhenCollapsed);\n }\n this.notify();\n }\n\n // === EXIT ===\n\n signalExit(callback: () => void): void {\n this.shouldExit = true;\n this.exitCallback = callback;\n this.notify();\n }\n\n getShouldExit = (): boolean => this.shouldExit;\n getExitCallback = (): (() => void) | null => this.exitCallback;\n\n // === RESET ===\n\n reset(): void {\n // Dispose terminal buffers before clearing\n for (const process of this.processes) {\n process.terminalBuffer?.dispose();\n }\n this.processes = [];\n this.completedIds = [];\n this.shouldExit = false;\n this.exitCallback = null;\n this.mode = 'normal';\n this.listNav.reset();\n this.expandedId = null;\n this.errorFooterExpanded = false;\n this.filterMode = 'all';\n this.searchTerm = '';\n this.isSearching = false;\n this.isFullscreen = false;\n this.header = undefined;\n }\n\n // === INFRASTRUCTURE ===\n\n notify(): void {\n this.bufferVersion++;\n this.listeners.forEach((l) => {\n l();\n });\n }\n}\n\n// Note: No global singleton - session creates its own store instance\n"],"names":["ProcessStore","FILTER_CYCLE","options","processes","completedIds","mode","expandedId","errorFooterExpanded","filterMode","searchTerm","isSearching","isFullscreen","showStatusBar","isInteractive","listeners","Set","shouldExit","exitCallback","bufferVersion","subscribe","listener","add","delete","getSnapshot","getRunningProcesses","filter","p","state","getCompletedProcesses","map","id","arrayFind","undefined","getFailedProcesses","getRunningCount","length","getMaxGroupLength","Math","DEFAULT_COLUMN_WIDTH","max","group","title","getDoneCount","getErrorCount","getErrorLineCount","reduce","total","getProcessLineCount","getMode","getSelectedIndex","listNav","position","getExpandedId","getListScrollOffset","viewportOffset","getErrorFooterExpanded","getBufferVersion","getFilterMode","getSearchTerm","getIsSearching","getIsFullscreen","getFilteredProcesses","filtered","term","toLowerCase","includes","getScrollOffset","process","getProcess","scrollNav","getHeader","header","getShowStatusBar","getIsInteractive","isAllComplete","every","getShouldExit","getExitCallback","interactive","createNavigator","getLength","wrap","onMove","notify","getErrorLines","processName","lines","getProcessLines","addProcess","processWithNav","updateProcess","update","oldProcess","wasRunning","isNowComplete","appendLines","newLines","concat","terminalBuffer","getLines","text","type","LineType","stdout","lineCount","setMode","setPosition","getSelectedProcess","cycleFilterNext","currentIndex","indexOf","toStart","cycleFilterPrev","startSearch","updateSearchTerm","cancelSearch","confirmSearch","clearSearch","enterFullscreen","exitFullscreen","toggleErrorFooter","expandErrorFooter","selectNext","visibleCount","down","ensureVisible","selectPrev","up","selectPageDown","pageSize","pageDown","selectPageUp","pageUp","selectFirst","selectLast","toEnd","clampListViewport","changed","clampViewport","getExpandedNav","nav","scrollDown","maxVisible","expanded","maxOffset","scrollUp","scrollPageDown","newPosition","min","scrollPageUp","scrollToTop","scrollToBottom","toggleExpand","visibleCountWhenExpanded","visibleCountWhenCollapsed","selected","collapse","signalExit","callback","reset","dispose","forEach","l"],"mappings":"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"}
|
|
@@ -7,6 +7,7 @@ import CompactProcessLine from './CompactProcessLine.js';
|
|
|
7
7
|
import Divider from './Divider.js';
|
|
8
8
|
import ErrorFooter from './ErrorFooter.js';
|
|
9
9
|
import ExpandedOutput from './ExpandedOutput.js';
|
|
10
|
+
import FullscreenOverlay from './FullscreenOverlay.js';
|
|
10
11
|
import StatusBar from './StatusBar.js';
|
|
11
12
|
const isMac = process.platform === 'darwin';
|
|
12
13
|
function AppContent({ store }) {
|
|
@@ -15,7 +16,7 @@ function AppContent({ store }) {
|
|
|
15
16
|
const { stdout } = useStdout();
|
|
16
17
|
const terminalHeight = (stdout === null || stdout === void 0 ? void 0 : stdout.rows) || 24;
|
|
17
18
|
// Subscribe to store state
|
|
18
|
-
const
|
|
19
|
+
const allProcesses = useSyncExternalStore(store.subscribe, store.getSnapshot);
|
|
19
20
|
const shouldExit = useSyncExternalStore(store.subscribe, store.getShouldExit);
|
|
20
21
|
const mode = useSyncExternalStore(store.subscribe, store.getMode);
|
|
21
22
|
const selectedIndex = useSyncExternalStore(store.subscribe, store.getSelectedIndex);
|
|
@@ -23,26 +24,40 @@ function AppContent({ store }) {
|
|
|
23
24
|
const scrollOffset = useSyncExternalStore(store.subscribe, store.getScrollOffset);
|
|
24
25
|
const listScrollOffset = useSyncExternalStore(store.subscribe, store.getListScrollOffset);
|
|
25
26
|
const errorFooterExpanded = useSyncExternalStore(store.subscribe, store.getErrorFooterExpanded);
|
|
27
|
+
const filterMode = useSyncExternalStore(store.subscribe, store.getFilterMode);
|
|
28
|
+
const searchTerm = useSyncExternalStore(store.subscribe, store.getSearchTerm);
|
|
29
|
+
const isSearching = useSyncExternalStore(store.subscribe, store.getIsSearching);
|
|
30
|
+
const isFullscreen = useSyncExternalStore(store.subscribe, store.getIsFullscreen);
|
|
26
31
|
// Subscribe to buffer version to trigger re-renders when terminal buffer content changes
|
|
27
32
|
const _bufferVersion = useSyncExternalStore(store.subscribe, store.getBufferVersion);
|
|
33
|
+
// Use filtered processes for display
|
|
34
|
+
const processes = store.getFilteredProcesses();
|
|
28
35
|
// Subscribed state that triggers re-renders
|
|
29
36
|
const header = useSyncExternalStore(store.subscribe, store.getHeader);
|
|
30
37
|
const showStatusBar = useSyncExternalStore(store.subscribe, store.getShowStatusBar);
|
|
31
38
|
const isInteractive = useSyncExternalStore(store.subscribe, store.getIsInteractive);
|
|
32
39
|
// Calculate visible process count (reserve lines for header, divider, status bar, expanded output)
|
|
33
40
|
// When a process is expanded, reserve space for the expanded output to prevent terminal scrolling
|
|
34
|
-
// In interactive mode without expansion, reserve space for
|
|
41
|
+
// In interactive mode without expansion, reserve space for filter bar and list scroll hint
|
|
35
42
|
const expandedHeight = expandedId ? EXPANDED_MAX_VISIBLE_LINES + 1 : 0; // +1 for scroll hint
|
|
43
|
+
const filterBarHeight = mode === 'interactive' && !expandedId ? 1 : 0; // Reserve for filter/search bar
|
|
36
44
|
const listHintHeight = mode === 'interactive' && !expandedId ? 1 : 0; // Reserve for list scroll hint
|
|
37
|
-
const reservedLines = (header ? 2 : 0) + (showStatusBar ? 2 : 0) + expandedHeight + listHintHeight;
|
|
45
|
+
const reservedLines = (header ? 2 : 0) + (showStatusBar ? 2 : 0) + expandedHeight + filterBarHeight + listHintHeight;
|
|
38
46
|
const visibleProcessCount = Math.max(1, terminalHeight - reservedLines);
|
|
39
|
-
// Derived state (computed from
|
|
47
|
+
// Derived state (computed from allProcesses - total counts regardless of filter)
|
|
40
48
|
const runningCount = store.getRunningCount();
|
|
41
49
|
const doneCount = store.getDoneCount();
|
|
42
50
|
const errorCount = store.getErrorCount();
|
|
43
51
|
const errorLineCount = store.getErrorLineCount();
|
|
44
52
|
const _isAllComplete = store.isAllComplete();
|
|
45
53
|
const errorLines = store.getErrorLines();
|
|
54
|
+
// Filter mode display labels
|
|
55
|
+
const filterLabels = {
|
|
56
|
+
all: 'All',
|
|
57
|
+
running: 'Running',
|
|
58
|
+
finished: 'Finished',
|
|
59
|
+
failed: 'Failed'
|
|
60
|
+
};
|
|
46
61
|
// Handle exit signal
|
|
47
62
|
useEffect(()=>{
|
|
48
63
|
if (shouldExit) {
|
|
@@ -75,8 +90,42 @@ function AppContent({ store }) {
|
|
|
75
90
|
visibleProcessCount,
|
|
76
91
|
store
|
|
77
92
|
]);
|
|
93
|
+
// Calculate fullscreen visible lines (terminal height minus header and footer)
|
|
94
|
+
const fullscreenVisibleLines = Math.max(1, terminalHeight - 3); // -3 for title, divider, footer
|
|
78
95
|
// Keyboard handling (only active when raw mode is supported)
|
|
79
96
|
useInput((input, key)=>{
|
|
97
|
+
// Fullscreen mode input handling
|
|
98
|
+
if (isFullscreen) {
|
|
99
|
+
if (input === 'q' || key.escape) {
|
|
100
|
+
store.exitFullscreen();
|
|
101
|
+
} else if (key.meta && key.upArrow || input === 'g') {
|
|
102
|
+
store.scrollToTop();
|
|
103
|
+
} else if (key.meta && key.downArrow || input === 'G') {
|
|
104
|
+
store.scrollToBottom(fullscreenVisibleLines);
|
|
105
|
+
} else if (key.tab && key.shift) {
|
|
106
|
+
store.scrollPageUp(fullscreenVisibleLines);
|
|
107
|
+
} else if (key.tab && !key.shift) {
|
|
108
|
+
store.scrollPageDown(fullscreenVisibleLines);
|
|
109
|
+
} else if (key.downArrow || input === 'j') {
|
|
110
|
+
store.scrollDown(fullscreenVisibleLines);
|
|
111
|
+
} else if (key.upArrow || input === 'k') {
|
|
112
|
+
store.scrollUp();
|
|
113
|
+
}
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
// Search mode input handling
|
|
117
|
+
if (isSearching) {
|
|
118
|
+
if (key.escape) {
|
|
119
|
+
store.cancelSearch();
|
|
120
|
+
} else if (key.return) {
|
|
121
|
+
store.confirmSearch();
|
|
122
|
+
} else if (key.backspace || key.delete) {
|
|
123
|
+
store.updateSearchTerm(searchTerm.slice(0, -1));
|
|
124
|
+
} else if (input && !key.ctrl && !key.meta) {
|
|
125
|
+
store.updateSearchTerm(searchTerm + input);
|
|
126
|
+
}
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
80
129
|
if (mode === 'normal') {
|
|
81
130
|
// In non-interactive mode, 'e' toggles error footer
|
|
82
131
|
if (input === 'e' && errorCount > 0) {
|
|
@@ -86,15 +135,29 @@ function AppContent({ store }) {
|
|
|
86
135
|
// Pre-calculate visible counts for expand/collapse transitions
|
|
87
136
|
const baseReserved = (header ? 2 : 0) + (showStatusBar ? 2 : 0);
|
|
88
137
|
const visibleWhenExpanded = Math.max(1, terminalHeight - baseReserved - EXPANDED_MAX_VISIBLE_LINES - 1);
|
|
89
|
-
const visibleWhenCollapsed = Math.max(1, terminalHeight - baseReserved -
|
|
138
|
+
const visibleWhenCollapsed = Math.max(1, terminalHeight - baseReserved - 2); // -2 for filter bar + list hint
|
|
90
139
|
if (input === 'q' || key.escape) {
|
|
91
140
|
if (expandedId) {
|
|
92
141
|
store.collapse(visibleWhenCollapsed);
|
|
142
|
+
} else if (searchTerm) {
|
|
143
|
+
// Clear search first before exiting
|
|
144
|
+
store.clearSearch();
|
|
93
145
|
} else {
|
|
94
146
|
store.signalExit(()=>{});
|
|
95
147
|
}
|
|
96
148
|
} else if (key.return) {
|
|
97
149
|
store.toggleExpand(visibleWhenExpanded, visibleWhenCollapsed);
|
|
150
|
+
// Fullscreen - 'f' to enter fullscreen when expanded
|
|
151
|
+
} else if (input === 'f' && expandedId) {
|
|
152
|
+
store.enterFullscreen();
|
|
153
|
+
// Filter cycling - left/right arrows
|
|
154
|
+
} else if (key.rightArrow && !expandedId) {
|
|
155
|
+
store.cycleFilterNext();
|
|
156
|
+
} else if (key.leftArrow && !expandedId) {
|
|
157
|
+
store.cycleFilterPrev();
|
|
158
|
+
// Search - '/' to start search
|
|
159
|
+
} else if (input === '/' && !expandedId) {
|
|
160
|
+
store.startSearch();
|
|
98
161
|
// Jump to top - Option+↑ (detected as meta), vim: g
|
|
99
162
|
// Must check meta+arrow BEFORE plain arrow
|
|
100
163
|
} else if (key.meta && key.upArrow || input === 'g') {
|
|
@@ -157,7 +220,18 @@ function AppContent({ store }) {
|
|
|
157
220
|
const showSelection = mode === 'interactive';
|
|
158
221
|
// Force full re-render when layout structure changes
|
|
159
222
|
// Note: scrollOffset is NOT included - scrolling within expansion doesn't change structure
|
|
160
|
-
const layoutKey = `${listScrollOffset}-${expandedId}-${errorCount}-${errorFooterExpanded}`;
|
|
223
|
+
const layoutKey = `${listScrollOffset}-${expandedId}-${errorCount}-${errorFooterExpanded}-${filterMode}-${searchTerm}-${isSearching}`;
|
|
224
|
+
// Get expanded process info for fullscreen
|
|
225
|
+
const expandedProcess = expandedId ? store.getProcess(expandedId) : null;
|
|
226
|
+
// Render fullscreen overlay when active
|
|
227
|
+
if (isFullscreen && expandedProcess) {
|
|
228
|
+
return /*#__PURE__*/ _jsx(FullscreenOverlay, {
|
|
229
|
+
title: expandedProcess.group || expandedProcess.title,
|
|
230
|
+
lines: store.getProcessLines(expandedProcess.id),
|
|
231
|
+
scrollOffset: scrollOffset,
|
|
232
|
+
onExit: ()=>store.exitFullscreen()
|
|
233
|
+
});
|
|
234
|
+
}
|
|
161
235
|
return /*#__PURE__*/ _jsxs(Box, {
|
|
162
236
|
flexDirection: "column",
|
|
163
237
|
children: [
|
|
@@ -169,6 +243,60 @@ function AppContent({ store }) {
|
|
|
169
243
|
/*#__PURE__*/ _jsx(Divider, {})
|
|
170
244
|
]
|
|
171
245
|
}),
|
|
246
|
+
mode === 'interactive' && !expandedId && /*#__PURE__*/ _jsxs(Box, {
|
|
247
|
+
children: [
|
|
248
|
+
/*#__PURE__*/ _jsx(Text, {
|
|
249
|
+
dimColor: true,
|
|
250
|
+
children: "◀ "
|
|
251
|
+
}),
|
|
252
|
+
/*#__PURE__*/ _jsx(Text, {
|
|
253
|
+
color: filterMode === 'running' ? 'yellow' : filterMode === 'failed' ? 'red' : filterMode === 'finished' ? 'green' : 'cyan',
|
|
254
|
+
bold: true,
|
|
255
|
+
children: filterLabels[filterMode]
|
|
256
|
+
}),
|
|
257
|
+
/*#__PURE__*/ _jsx(Text, {
|
|
258
|
+
dimColor: true,
|
|
259
|
+
children: " ▶"
|
|
260
|
+
}),
|
|
261
|
+
isSearching ? /*#__PURE__*/ _jsxs(Text, {
|
|
262
|
+
children: [
|
|
263
|
+
' ',
|
|
264
|
+
/*#__PURE__*/ _jsx(Text, {
|
|
265
|
+
dimColor: true,
|
|
266
|
+
children: "/"
|
|
267
|
+
}),
|
|
268
|
+
/*#__PURE__*/ _jsx(Text, {
|
|
269
|
+
children: searchTerm
|
|
270
|
+
}),
|
|
271
|
+
/*#__PURE__*/ _jsx(Text, {
|
|
272
|
+
dimColor: true,
|
|
273
|
+
children: "▋"
|
|
274
|
+
})
|
|
275
|
+
]
|
|
276
|
+
}) : searchTerm ? /*#__PURE__*/ _jsxs(Text, {
|
|
277
|
+
dimColor: true,
|
|
278
|
+
children: [
|
|
279
|
+
' "',
|
|
280
|
+
searchTerm,
|
|
281
|
+
'"'
|
|
282
|
+
]
|
|
283
|
+
}) : /*#__PURE__*/ _jsx(Text, {
|
|
284
|
+
dimColor: true,
|
|
285
|
+
children: " (/ search)"
|
|
286
|
+
}),
|
|
287
|
+
processes.length !== allProcesses.length && /*#__PURE__*/ _jsxs(Text, {
|
|
288
|
+
dimColor: true,
|
|
289
|
+
children: [
|
|
290
|
+
' ',
|
|
291
|
+
"[",
|
|
292
|
+
processes.length,
|
|
293
|
+
"/",
|
|
294
|
+
allProcesses.length,
|
|
295
|
+
"]"
|
|
296
|
+
]
|
|
297
|
+
})
|
|
298
|
+
]
|
|
299
|
+
}),
|
|
172
300
|
/*#__PURE__*/ _jsxs(Box, {
|
|
173
301
|
flexDirection: "column",
|
|
174
302
|
children: [
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/node/spawn-term/src/components/App.tsx"],"sourcesContent":["import { Box, Text, useApp, useInput, useStdin, useStdout } from 'ink';\nimport { useEffect, useMemo, useSyncExternalStore } from 'react';\nimport { EXPANDED_MAX_VISIBLE_LINES } from '../constants.ts';\nimport type { ProcessStore } from '../state/processStore.ts';\nimport { StoreContext } from '../state/StoreContext.ts';\nimport CompactProcessLine from './CompactProcessLine.ts';\nimport Divider from './Divider.ts';\nimport ErrorFooter from './ErrorFooter.ts';\nimport ExpandedOutput from './ExpandedOutput.ts';\nimport StatusBar from './StatusBar.ts';\n\nconst isMac = process.platform === 'darwin';\n\ninterface AppProps {\n store: ProcessStore;\n}\n\nfunction AppContent({ store }: AppProps): React.JSX.Element {\n const { exit } = useApp();\n const { isRawModeSupported } = useStdin();\n const { stdout } = useStdout();\n const terminalHeight = stdout?.rows || 24;\n\n // Subscribe to store state\n const processes = useSyncExternalStore(store.subscribe, store.getSnapshot);\n const shouldExit = useSyncExternalStore(store.subscribe, store.getShouldExit);\n const mode = useSyncExternalStore(store.subscribe, store.getMode);\n const selectedIndex = useSyncExternalStore(store.subscribe, store.getSelectedIndex);\n const expandedId = useSyncExternalStore(store.subscribe, store.getExpandedId);\n const scrollOffset = useSyncExternalStore(store.subscribe, store.getScrollOffset);\n const listScrollOffset = useSyncExternalStore(store.subscribe, store.getListScrollOffset);\n const errorFooterExpanded = useSyncExternalStore(store.subscribe, store.getErrorFooterExpanded);\n // Subscribe to buffer version to trigger re-renders when terminal buffer content changes\n const _bufferVersion = useSyncExternalStore(store.subscribe, store.getBufferVersion);\n\n // Subscribed state that triggers re-renders\n const header = useSyncExternalStore(store.subscribe, store.getHeader);\n const showStatusBar = useSyncExternalStore(store.subscribe, store.getShowStatusBar);\n const isInteractive = useSyncExternalStore(store.subscribe, store.getIsInteractive);\n\n // Calculate visible process count (reserve lines for header, divider, status bar, expanded output)\n // When a process is expanded, reserve space for the expanded output to prevent terminal scrolling\n // In interactive mode without expansion, reserve space for potential list scroll hint\n const expandedHeight = expandedId ? EXPANDED_MAX_VISIBLE_LINES + 1 : 0; // +1 for scroll hint\n const listHintHeight = mode === 'interactive' && !expandedId ? 1 : 0; // Reserve for list scroll hint\n const reservedLines = (header ? 2 : 0) + (showStatusBar ? 2 : 0) + expandedHeight + listHintHeight;\n const visibleProcessCount = Math.max(1, terminalHeight - reservedLines);\n\n // Derived state (computed from processes which is already subscribed)\n const runningCount = store.getRunningCount();\n const doneCount = store.getDoneCount();\n const errorCount = store.getErrorCount();\n const errorLineCount = store.getErrorLineCount();\n const _isAllComplete = store.isAllComplete();\n const errorLines = store.getErrorLines();\n\n // Handle exit signal\n useEffect(() => {\n if (shouldExit) {\n exit();\n }\n }, [shouldExit, exit]);\n\n // Auto-enter interactive mode immediately when interactive flag is set\n // This allows selecting and viewing logs of running processes\n useEffect(() => {\n if (isInteractive && mode === 'normal') {\n store.setMode('interactive');\n }\n }, [isInteractive, mode, store]);\n\n // Clamp viewport when collapsing to avoid empty space\n // This runs after render with correct visibleProcessCount\n useEffect(() => {\n if (mode === 'interactive' && !expandedId) {\n store.clampListViewport(visibleProcessCount);\n }\n }, [mode, expandedId, visibleProcessCount, store]);\n\n // Keyboard handling (only active when raw mode is supported)\n useInput(\n (input, key) => {\n if (mode === 'normal') {\n // In non-interactive mode, 'e' toggles error footer\n if (input === 'e' && errorCount > 0) {\n store.toggleErrorFooter();\n }\n } else if (mode === 'interactive') {\n // Pre-calculate visible counts for expand/collapse transitions\n const baseReserved = (header ? 2 : 0) + (showStatusBar ? 2 : 0);\n const visibleWhenExpanded = Math.max(1, terminalHeight - baseReserved - EXPANDED_MAX_VISIBLE_LINES - 1);\n const visibleWhenCollapsed = Math.max(1, terminalHeight - baseReserved - 1); // -1 for list hint\n\n if (input === 'q' || key.escape) {\n if (expandedId) {\n store.collapse(visibleWhenCollapsed);\n } else {\n store.signalExit(() => {});\n }\n } else if (key.return) {\n store.toggleExpand(visibleWhenExpanded, visibleWhenCollapsed);\n // Jump to top - Option+↑ (detected as meta), vim: g\n // Must check meta+arrow BEFORE plain arrow\n } else if ((key.meta && key.upArrow) || input === 'g') {\n if (expandedId) {\n store.scrollToTop();\n } else {\n store.selectFirst(visibleProcessCount);\n }\n // Jump to bottom - Option+↓ (detected as meta), vim: G\n } else if ((key.meta && key.downArrow) || input === 'G') {\n if (expandedId) {\n store.scrollToBottom(EXPANDED_MAX_VISIBLE_LINES);\n } else {\n store.selectLast(visibleProcessCount);\n }\n // Page scrolling - Tab/Shift+Tab (use same page size as expanded view)\n } else if (key.tab && key.shift) {\n if (expandedId) {\n store.scrollPageUp(EXPANDED_MAX_VISIBLE_LINES);\n } else {\n store.selectPageUp(EXPANDED_MAX_VISIBLE_LINES, visibleProcessCount);\n }\n } else if (key.tab && !key.shift) {\n if (expandedId) {\n store.scrollPageDown(EXPANDED_MAX_VISIBLE_LINES);\n } else {\n store.selectPageDown(EXPANDED_MAX_VISIBLE_LINES, visibleProcessCount);\n }\n // Line scrolling - arrows and vim j/k\n } else if (key.downArrow || input === 'j') {\n if (expandedId) {\n store.scrollDown(EXPANDED_MAX_VISIBLE_LINES);\n } else {\n store.selectNext(visibleProcessCount);\n }\n } else if (key.upArrow || input === 'k') {\n if (expandedId) {\n store.scrollUp();\n } else {\n store.selectPrev(visibleProcessCount);\n }\n }\n }\n },\n { isActive: isRawModeSupported === true }\n );\n\n // Slice processes to visible viewport in interactive mode\n const visibleProcesses = useMemo(() => {\n if (mode === 'interactive') {\n return processes.slice(listScrollOffset, listScrollOffset + visibleProcessCount);\n }\n return processes;\n }, [processes, mode, listScrollOffset, visibleProcessCount]);\n\n // Normal/Interactive view - render in original registration order\n const showSelection = mode === 'interactive';\n\n // Force full re-render when layout structure changes\n // Note: scrollOffset is NOT included - scrolling within expansion doesn't change structure\n const layoutKey = `${listScrollOffset}-${expandedId}-${errorCount}-${errorFooterExpanded}`;\n\n return (\n <Box key={layoutKey} flexDirection=\"column\">\n {/* Header */}\n {header && (\n <>\n <Text>{header}</Text>\n <Divider />\n </>\n )}\n\n {/* Visible processes */}\n <Box flexDirection=\"column\">\n {visibleProcesses.map((item) => {\n const originalIndex = processes.indexOf(item);\n return (\n <Box key={item.id} flexDirection=\"column\">\n <CompactProcessLine item={item} isSelected={showSelection && originalIndex === selectedIndex} />\n {expandedId === item.id && <ExpandedOutput lines={store.getProcessLines(item.id)} scrollOffset={scrollOffset} />}\n </Box>\n );\n })}\n {/* List scroll hint (interactive mode without expansion) */}\n {mode === 'interactive' && !expandedId && processes.length > visibleProcessCount && (\n <Text dimColor>\n [+{processes.length - visibleProcessCount} more, Tab/⇧Tab page, {isMac ? '⌥↑/↓' : 'g/G'} top/bottom]\n </Text>\n )}\n </Box>\n\n {/* Status bar */}\n {showStatusBar && processes.length > 0 && (\n <>\n <Divider />\n <StatusBar running={runningCount} done={doneCount} errors={errorCount} errorLines={errorLineCount} />\n </>\n )}\n\n {/* Error footer (non-interactive mode only) */}\n {!isInteractive && errorCount > 0 && <ErrorFooter errors={errorLines} isExpanded={errorFooterExpanded} />}\n </Box>\n );\n}\n\n// Wrapper component that provides store context\nexport default function App({ store }: AppProps): React.JSX.Element {\n return (\n <StoreContext.Provider value={store}>\n <AppContent store={store} />\n </StoreContext.Provider>\n );\n}\n"],"names":["Box","Text","useApp","useInput","useStdin","useStdout","useEffect","useMemo","useSyncExternalStore","EXPANDED_MAX_VISIBLE_LINES","StoreContext","CompactProcessLine","Divider","ErrorFooter","ExpandedOutput","StatusBar","isMac","process","platform","AppContent","store","exit","isRawModeSupported","stdout","terminalHeight","rows","processes","subscribe","getSnapshot","shouldExit","getShouldExit","mode","getMode","selectedIndex","getSelectedIndex","expandedId","getExpandedId","scrollOffset","getScrollOffset","listScrollOffset","getListScrollOffset","errorFooterExpanded","getErrorFooterExpanded","_bufferVersion","getBufferVersion","header","getHeader","showStatusBar","getShowStatusBar","isInteractive","getIsInteractive","expandedHeight","listHintHeight","reservedLines","visibleProcessCount","Math","max","runningCount","getRunningCount","doneCount","getDoneCount","errorCount","getErrorCount","errorLineCount","getErrorLineCount","_isAllComplete","isAllComplete","errorLines","getErrorLines","setMode","clampListViewport","input","key","toggleErrorFooter","baseReserved","visibleWhenExpanded","visibleWhenCollapsed","escape","collapse","signalExit","return","toggleExpand","meta","upArrow","scrollToTop","selectFirst","downArrow","scrollToBottom","selectLast","tab","shift","scrollPageUp","selectPageUp","scrollPageDown","selectPageDown","scrollDown","selectNext","scrollUp","selectPrev","isActive","visibleProcesses","slice","showSelection","layoutKey","flexDirection","map","item","originalIndex","indexOf","isSelected","id","lines","getProcessLines","length","dimColor","running","done","errors","isExpanded","App","Provider","value"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/node/spawn-term/src/components/App.tsx"],"sourcesContent":["import { Box, Text, useApp, useInput, useStdin, useStdout } from 'ink';\nimport { useEffect, useMemo, useSyncExternalStore } from 'react';\nimport { EXPANDED_MAX_VISIBLE_LINES } from '../constants.ts';\nimport type { ProcessStore } from '../state/processStore.ts';\nimport { StoreContext } from '../state/StoreContext.ts';\nimport CompactProcessLine from './CompactProcessLine.ts';\nimport Divider from './Divider.ts';\nimport ErrorFooter from './ErrorFooter.ts';\nimport ExpandedOutput from './ExpandedOutput.ts';\nimport FullscreenOverlay from './FullscreenOverlay.ts';\nimport StatusBar from './StatusBar.ts';\n\nconst isMac = process.platform === 'darwin';\n\ninterface AppProps {\n store: ProcessStore;\n}\n\nfunction AppContent({ store }: AppProps): React.JSX.Element {\n const { exit } = useApp();\n const { isRawModeSupported } = useStdin();\n const { stdout } = useStdout();\n const terminalHeight = stdout?.rows || 24;\n\n // Subscribe to store state\n const allProcesses = useSyncExternalStore(store.subscribe, store.getSnapshot);\n const shouldExit = useSyncExternalStore(store.subscribe, store.getShouldExit);\n const mode = useSyncExternalStore(store.subscribe, store.getMode);\n const selectedIndex = useSyncExternalStore(store.subscribe, store.getSelectedIndex);\n const expandedId = useSyncExternalStore(store.subscribe, store.getExpandedId);\n const scrollOffset = useSyncExternalStore(store.subscribe, store.getScrollOffset);\n const listScrollOffset = useSyncExternalStore(store.subscribe, store.getListScrollOffset);\n const errorFooterExpanded = useSyncExternalStore(store.subscribe, store.getErrorFooterExpanded);\n const filterMode = useSyncExternalStore(store.subscribe, store.getFilterMode);\n const searchTerm = useSyncExternalStore(store.subscribe, store.getSearchTerm);\n const isSearching = useSyncExternalStore(store.subscribe, store.getIsSearching);\n const isFullscreen = useSyncExternalStore(store.subscribe, store.getIsFullscreen);\n // Subscribe to buffer version to trigger re-renders when terminal buffer content changes\n const _bufferVersion = useSyncExternalStore(store.subscribe, store.getBufferVersion);\n\n // Use filtered processes for display\n const processes = store.getFilteredProcesses();\n\n // Subscribed state that triggers re-renders\n const header = useSyncExternalStore(store.subscribe, store.getHeader);\n const showStatusBar = useSyncExternalStore(store.subscribe, store.getShowStatusBar);\n const isInteractive = useSyncExternalStore(store.subscribe, store.getIsInteractive);\n\n // Calculate visible process count (reserve lines for header, divider, status bar, expanded output)\n // When a process is expanded, reserve space for the expanded output to prevent terminal scrolling\n // In interactive mode without expansion, reserve space for filter bar and list scroll hint\n const expandedHeight = expandedId ? EXPANDED_MAX_VISIBLE_LINES + 1 : 0; // +1 for scroll hint\n const filterBarHeight = mode === 'interactive' && !expandedId ? 1 : 0; // Reserve for filter/search bar\n const listHintHeight = mode === 'interactive' && !expandedId ? 1 : 0; // Reserve for list scroll hint\n const reservedLines = (header ? 2 : 0) + (showStatusBar ? 2 : 0) + expandedHeight + filterBarHeight + listHintHeight;\n const visibleProcessCount = Math.max(1, terminalHeight - reservedLines);\n\n // Derived state (computed from allProcesses - total counts regardless of filter)\n const runningCount = store.getRunningCount();\n const doneCount = store.getDoneCount();\n const errorCount = store.getErrorCount();\n const errorLineCount = store.getErrorLineCount();\n const _isAllComplete = store.isAllComplete();\n const errorLines = store.getErrorLines();\n\n // Filter mode display labels\n const filterLabels: Record<string, string> = {\n all: 'All',\n running: 'Running',\n finished: 'Finished',\n failed: 'Failed',\n };\n\n // Handle exit signal\n useEffect(() => {\n if (shouldExit) {\n exit();\n }\n }, [shouldExit, exit]);\n\n // Auto-enter interactive mode immediately when interactive flag is set\n // This allows selecting and viewing logs of running processes\n useEffect(() => {\n if (isInteractive && mode === 'normal') {\n store.setMode('interactive');\n }\n }, [isInteractive, mode, store]);\n\n // Clamp viewport when collapsing to avoid empty space\n // This runs after render with correct visibleProcessCount\n useEffect(() => {\n if (mode === 'interactive' && !expandedId) {\n store.clampListViewport(visibleProcessCount);\n }\n }, [mode, expandedId, visibleProcessCount, store]);\n\n // Calculate fullscreen visible lines (terminal height minus header and footer)\n const fullscreenVisibleLines = Math.max(1, terminalHeight - 3); // -3 for title, divider, footer\n\n // Keyboard handling (only active when raw mode is supported)\n useInput(\n (input, key) => {\n // Fullscreen mode input handling\n if (isFullscreen) {\n if (input === 'q' || key.escape) {\n store.exitFullscreen();\n } else if ((key.meta && key.upArrow) || input === 'g') {\n store.scrollToTop();\n } else if ((key.meta && key.downArrow) || input === 'G') {\n store.scrollToBottom(fullscreenVisibleLines);\n } else if (key.tab && key.shift) {\n store.scrollPageUp(fullscreenVisibleLines);\n } else if (key.tab && !key.shift) {\n store.scrollPageDown(fullscreenVisibleLines);\n } else if (key.downArrow || input === 'j') {\n store.scrollDown(fullscreenVisibleLines);\n } else if (key.upArrow || input === 'k') {\n store.scrollUp();\n }\n return;\n }\n\n // Search mode input handling\n if (isSearching) {\n if (key.escape) {\n store.cancelSearch();\n } else if (key.return) {\n store.confirmSearch();\n } else if (key.backspace || key.delete) {\n store.updateSearchTerm(searchTerm.slice(0, -1));\n } else if (input && !key.ctrl && !key.meta) {\n store.updateSearchTerm(searchTerm + input);\n }\n return;\n }\n\n if (mode === 'normal') {\n // In non-interactive mode, 'e' toggles error footer\n if (input === 'e' && errorCount > 0) {\n store.toggleErrorFooter();\n }\n } else if (mode === 'interactive') {\n // Pre-calculate visible counts for expand/collapse transitions\n const baseReserved = (header ? 2 : 0) + (showStatusBar ? 2 : 0);\n const visibleWhenExpanded = Math.max(1, terminalHeight - baseReserved - EXPANDED_MAX_VISIBLE_LINES - 1);\n const visibleWhenCollapsed = Math.max(1, terminalHeight - baseReserved - 2); // -2 for filter bar + list hint\n\n if (input === 'q' || key.escape) {\n if (expandedId) {\n store.collapse(visibleWhenCollapsed);\n } else if (searchTerm) {\n // Clear search first before exiting\n store.clearSearch();\n } else {\n store.signalExit(() => {});\n }\n } else if (key.return) {\n store.toggleExpand(visibleWhenExpanded, visibleWhenCollapsed);\n // Fullscreen - 'f' to enter fullscreen when expanded\n } else if (input === 'f' && expandedId) {\n store.enterFullscreen();\n // Filter cycling - left/right arrows\n } else if (key.rightArrow && !expandedId) {\n store.cycleFilterNext();\n } else if (key.leftArrow && !expandedId) {\n store.cycleFilterPrev();\n // Search - '/' to start search\n } else if (input === '/' && !expandedId) {\n store.startSearch();\n // Jump to top - Option+↑ (detected as meta), vim: g\n // Must check meta+arrow BEFORE plain arrow\n } else if ((key.meta && key.upArrow) || input === 'g') {\n if (expandedId) {\n store.scrollToTop();\n } else {\n store.selectFirst(visibleProcessCount);\n }\n // Jump to bottom - Option+↓ (detected as meta), vim: G\n } else if ((key.meta && key.downArrow) || input === 'G') {\n if (expandedId) {\n store.scrollToBottom(EXPANDED_MAX_VISIBLE_LINES);\n } else {\n store.selectLast(visibleProcessCount);\n }\n // Page scrolling - Tab/Shift+Tab (use same page size as expanded view)\n } else if (key.tab && key.shift) {\n if (expandedId) {\n store.scrollPageUp(EXPANDED_MAX_VISIBLE_LINES);\n } else {\n store.selectPageUp(EXPANDED_MAX_VISIBLE_LINES, visibleProcessCount);\n }\n } else if (key.tab && !key.shift) {\n if (expandedId) {\n store.scrollPageDown(EXPANDED_MAX_VISIBLE_LINES);\n } else {\n store.selectPageDown(EXPANDED_MAX_VISIBLE_LINES, visibleProcessCount);\n }\n // Line scrolling - arrows and vim j/k\n } else if (key.downArrow || input === 'j') {\n if (expandedId) {\n store.scrollDown(EXPANDED_MAX_VISIBLE_LINES);\n } else {\n store.selectNext(visibleProcessCount);\n }\n } else if (key.upArrow || input === 'k') {\n if (expandedId) {\n store.scrollUp();\n } else {\n store.selectPrev(visibleProcessCount);\n }\n }\n }\n },\n { isActive: isRawModeSupported === true }\n );\n\n // Slice processes to visible viewport in interactive mode\n const visibleProcesses = useMemo(() => {\n if (mode === 'interactive') {\n return processes.slice(listScrollOffset, listScrollOffset + visibleProcessCount);\n }\n return processes;\n }, [processes, mode, listScrollOffset, visibleProcessCount]);\n\n // Normal/Interactive view - render in original registration order\n const showSelection = mode === 'interactive';\n\n // Force full re-render when layout structure changes\n // Note: scrollOffset is NOT included - scrolling within expansion doesn't change structure\n const layoutKey = `${listScrollOffset}-${expandedId}-${errorCount}-${errorFooterExpanded}-${filterMode}-${searchTerm}-${isSearching}`;\n\n // Get expanded process info for fullscreen\n const expandedProcess = expandedId ? store.getProcess(expandedId) : null;\n\n // Render fullscreen overlay when active\n if (isFullscreen && expandedProcess) {\n return <FullscreenOverlay title={expandedProcess.group || expandedProcess.title} lines={store.getProcessLines(expandedProcess.id)} scrollOffset={scrollOffset} onExit={() => store.exitFullscreen()} />;\n }\n\n return (\n <Box key={layoutKey} flexDirection=\"column\">\n {/* Header */}\n {header && (\n <>\n <Text>{header}</Text>\n <Divider />\n </>\n )}\n\n {/* Filter/Search bar (interactive mode only) */}\n {mode === 'interactive' && !expandedId && (\n <Box>\n <Text dimColor>◀ </Text>\n <Text color={filterMode === 'running' ? 'yellow' : filterMode === 'failed' ? 'red' : filterMode === 'finished' ? 'green' : 'cyan'} bold>\n {filterLabels[filterMode]}\n </Text>\n <Text dimColor> ▶</Text>\n {isSearching ? (\n <Text>\n {' '}\n <Text dimColor>/</Text>\n <Text>{searchTerm}</Text>\n <Text dimColor>▋</Text>\n </Text>\n ) : searchTerm ? (\n <Text dimColor> \"{searchTerm}\"</Text>\n ) : (\n <Text dimColor> (/ search)</Text>\n )}\n {processes.length !== allProcesses.length && (\n <Text dimColor>\n {' '}\n [{processes.length}/{allProcesses.length}]\n </Text>\n )}\n </Box>\n )}\n\n {/* Visible processes */}\n <Box flexDirection=\"column\">\n {visibleProcesses.map((item) => {\n const originalIndex = processes.indexOf(item);\n return (\n <Box key={item.id} flexDirection=\"column\">\n <CompactProcessLine item={item} isSelected={showSelection && originalIndex === selectedIndex} />\n {expandedId === item.id && <ExpandedOutput lines={store.getProcessLines(item.id)} scrollOffset={scrollOffset} />}\n </Box>\n );\n })}\n {/* List scroll hint (interactive mode without expansion) */}\n {mode === 'interactive' && !expandedId && processes.length > visibleProcessCount && (\n <Text dimColor>\n [+{processes.length - visibleProcessCount} more, Tab/⇧Tab page, {isMac ? '⌥↑/↓' : 'g/G'} top/bottom]\n </Text>\n )}\n </Box>\n\n {/* Status bar */}\n {showStatusBar && processes.length > 0 && (\n <>\n <Divider />\n <StatusBar running={runningCount} done={doneCount} errors={errorCount} errorLines={errorLineCount} />\n </>\n )}\n\n {/* Error footer (non-interactive mode only) */}\n {!isInteractive && errorCount > 0 && <ErrorFooter errors={errorLines} isExpanded={errorFooterExpanded} />}\n </Box>\n );\n}\n\n// Wrapper component that provides store context\nexport default function App({ store }: AppProps): React.JSX.Element {\n return (\n <StoreContext.Provider value={store}>\n <AppContent store={store} />\n </StoreContext.Provider>\n );\n}\n"],"names":["Box","Text","useApp","useInput","useStdin","useStdout","useEffect","useMemo","useSyncExternalStore","EXPANDED_MAX_VISIBLE_LINES","StoreContext","CompactProcessLine","Divider","ErrorFooter","ExpandedOutput","FullscreenOverlay","StatusBar","isMac","process","platform","AppContent","store","exit","isRawModeSupported","stdout","terminalHeight","rows","allProcesses","subscribe","getSnapshot","shouldExit","getShouldExit","mode","getMode","selectedIndex","getSelectedIndex","expandedId","getExpandedId","scrollOffset","getScrollOffset","listScrollOffset","getListScrollOffset","errorFooterExpanded","getErrorFooterExpanded","filterMode","getFilterMode","searchTerm","getSearchTerm","isSearching","getIsSearching","isFullscreen","getIsFullscreen","_bufferVersion","getBufferVersion","processes","getFilteredProcesses","header","getHeader","showStatusBar","getShowStatusBar","isInteractive","getIsInteractive","expandedHeight","filterBarHeight","listHintHeight","reservedLines","visibleProcessCount","Math","max","runningCount","getRunningCount","doneCount","getDoneCount","errorCount","getErrorCount","errorLineCount","getErrorLineCount","_isAllComplete","isAllComplete","errorLines","getErrorLines","filterLabels","all","running","finished","failed","setMode","clampListViewport","fullscreenVisibleLines","input","key","escape","exitFullscreen","meta","upArrow","scrollToTop","downArrow","scrollToBottom","tab","shift","scrollPageUp","scrollPageDown","scrollDown","scrollUp","cancelSearch","return","confirmSearch","backspace","delete","updateSearchTerm","slice","ctrl","toggleErrorFooter","baseReserved","visibleWhenExpanded","visibleWhenCollapsed","collapse","clearSearch","signalExit","toggleExpand","enterFullscreen","rightArrow","cycleFilterNext","leftArrow","cycleFilterPrev","startSearch","selectFirst","selectLast","selectPageUp","selectPageDown","selectNext","selectPrev","isActive","visibleProcesses","showSelection","layoutKey","expandedProcess","getProcess","title","group","lines","getProcessLines","id","onExit","flexDirection","dimColor","color","bold","length","map","item","originalIndex","indexOf","isSelected","done","errors","isExpanded","App","Provider","value"],"mappings":"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"}
|