spawn-term 3.2.0 → 3.2.2
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 +48 -5
- 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 +4 -0
- package/dist/cjs/state/processStore.js +28 -0
- package/dist/cjs/state/processStore.js.map +1 -1
- package/dist/esm/components/App.js +41 -0
- 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 +4 -0
- package/dist/esm/state/processStore.js +26 -0
- package/dist/esm/state/processStore.js.map +1 -1
- package/package.json +1 -1
|
@@ -18,6 +18,7 @@ var _CompactProcessLinets = /*#__PURE__*/ _interop_require_default(require("./Co
|
|
|
18
18
|
var _Dividerts = /*#__PURE__*/ _interop_require_default(require("./Divider.js"));
|
|
19
19
|
var _ErrorFooterts = /*#__PURE__*/ _interop_require_default(require("./ErrorFooter.js"));
|
|
20
20
|
var _ExpandedOutputts = /*#__PURE__*/ _interop_require_default(require("./ExpandedOutput.js"));
|
|
21
|
+
var _FullscreenOverlayts = /*#__PURE__*/ _interop_require_default(require("./FullscreenOverlay.js"));
|
|
21
22
|
var _StatusBarts = /*#__PURE__*/ _interop_require_default(require("./StatusBar.js"));
|
|
22
23
|
function _interop_require_default(obj) {
|
|
23
24
|
return obj && obj.__esModule ? obj : {
|
|
@@ -43,6 +44,7 @@ function AppContent(param) {
|
|
|
43
44
|
var filterMode = (0, _react.useSyncExternalStore)(store.subscribe, store.getFilterMode);
|
|
44
45
|
var searchTerm = (0, _react.useSyncExternalStore)(store.subscribe, store.getSearchTerm);
|
|
45
46
|
var isSearching = (0, _react.useSyncExternalStore)(store.subscribe, store.getIsSearching);
|
|
47
|
+
var isFullscreen = (0, _react.useSyncExternalStore)(store.subscribe, store.getIsFullscreen);
|
|
46
48
|
// Subscribe to buffer version to trigger re-renders when terminal buffer content changes
|
|
47
49
|
var _bufferVersion = (0, _react.useSyncExternalStore)(store.subscribe, store.getBufferVersion);
|
|
48
50
|
// Use filtered processes for display
|
|
@@ -105,8 +107,32 @@ function AppContent(param) {
|
|
|
105
107
|
visibleProcessCount,
|
|
106
108
|
store
|
|
107
109
|
]);
|
|
110
|
+
// Calculate fullscreen visible lines (terminal height minus header and footer)
|
|
111
|
+
var fullscreenVisibleLines = Math.max(1, terminalHeight - 3); // -3 for title, divider, footer
|
|
108
112
|
// Keyboard handling (only active when raw mode is supported)
|
|
109
113
|
(0, _ink.useInput)(function(input, key) {
|
|
114
|
+
// Fullscreen mode input handling
|
|
115
|
+
if (isFullscreen) {
|
|
116
|
+
// Pre-calculate for viewport adjustment
|
|
117
|
+
var baseReserved = (header ? 2 : 0) + (showStatusBar ? 2 : 0);
|
|
118
|
+
var visibleWhenCollapsed = Math.max(1, terminalHeight - baseReserved - 2);
|
|
119
|
+
if (input === 'q' || key.escape || key.return) {
|
|
120
|
+
store.exitFullscreen(visibleWhenCollapsed);
|
|
121
|
+
} else if (key.meta && key.upArrow || input === 'g') {
|
|
122
|
+
store.scrollToTop();
|
|
123
|
+
} else if (key.meta && key.downArrow || input === 'G') {
|
|
124
|
+
store.scrollToBottom(fullscreenVisibleLines);
|
|
125
|
+
} else if (key.tab && key.shift) {
|
|
126
|
+
store.scrollPageUp(fullscreenVisibleLines);
|
|
127
|
+
} else if (key.tab && !key.shift) {
|
|
128
|
+
store.scrollPageDown(fullscreenVisibleLines);
|
|
129
|
+
} else if (key.downArrow || input === 'j') {
|
|
130
|
+
store.scrollDown(fullscreenVisibleLines);
|
|
131
|
+
} else if (key.upArrow || input === 'k') {
|
|
132
|
+
store.scrollUp();
|
|
133
|
+
}
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
110
136
|
// Search mode input handling
|
|
111
137
|
if (isSearching) {
|
|
112
138
|
if (key.escape) {
|
|
@@ -127,20 +153,24 @@ function AppContent(param) {
|
|
|
127
153
|
}
|
|
128
154
|
} else if (mode === 'interactive') {
|
|
129
155
|
// Pre-calculate visible counts for expand/collapse transitions
|
|
130
|
-
var
|
|
131
|
-
var visibleWhenExpanded = Math.max(1, terminalHeight -
|
|
132
|
-
var
|
|
156
|
+
var baseReserved1 = (header ? 2 : 0) + (showStatusBar ? 2 : 0);
|
|
157
|
+
var visibleWhenExpanded = Math.max(1, terminalHeight - baseReserved1 - _constantsts.EXPANDED_MAX_VISIBLE_LINES - 1);
|
|
158
|
+
var visibleWhenCollapsed1 = Math.max(1, terminalHeight - baseReserved1 - 2); // -2 for filter bar + list hint
|
|
133
159
|
if (input === 'q' || key.escape) {
|
|
134
160
|
if (expandedId) {
|
|
135
|
-
store.collapse(
|
|
161
|
+
store.collapse(visibleWhenCollapsed1);
|
|
136
162
|
} else if (searchTerm) {
|
|
137
163
|
// Clear search first before exiting
|
|
138
164
|
store.clearSearch();
|
|
139
165
|
} else {
|
|
140
166
|
store.signalExit(function() {});
|
|
141
167
|
}
|
|
168
|
+
// Enter - fullscreen view (direct from list or from expanded)
|
|
142
169
|
} else if (key.return) {
|
|
143
|
-
store.
|
|
170
|
+
store.enterFullscreen();
|
|
171
|
+
// Space - toggle small expanded preview
|
|
172
|
+
} else if (input === ' ') {
|
|
173
|
+
store.toggleExpand(visibleWhenExpanded, visibleWhenCollapsed1);
|
|
144
174
|
// Filter cycling - left/right arrows
|
|
145
175
|
} else if (key.rightArrow && !expandedId) {
|
|
146
176
|
store.cycleFilterNext();
|
|
@@ -212,6 +242,19 @@ function AppContent(param) {
|
|
|
212
242
|
// Force full re-render when layout structure changes
|
|
213
243
|
// Note: scrollOffset is NOT included - scrolling within expansion doesn't change structure
|
|
214
244
|
var layoutKey = "".concat(listScrollOffset, "-").concat(expandedId, "-").concat(errorCount, "-").concat(errorFooterExpanded, "-").concat(filterMode, "-").concat(searchTerm, "-").concat(isSearching);
|
|
245
|
+
// Get expanded process info for fullscreen
|
|
246
|
+
var expandedProcess = expandedId ? store.getProcess(expandedId) : null;
|
|
247
|
+
// Render fullscreen overlay when active
|
|
248
|
+
if (isFullscreen && expandedProcess) {
|
|
249
|
+
return /*#__PURE__*/ (0, _jsxruntime.jsx)(_FullscreenOverlayts.default, {
|
|
250
|
+
title: expandedProcess.group || expandedProcess.title,
|
|
251
|
+
lines: store.getProcessLines(expandedProcess.id),
|
|
252
|
+
scrollOffset: scrollOffset,
|
|
253
|
+
onExit: function() {
|
|
254
|
+
return store.exitFullscreen();
|
|
255
|
+
}
|
|
256
|
+
});
|
|
257
|
+
}
|
|
215
258
|
return /*#__PURE__*/ (0, _jsxruntime.jsxs)(_ink.Box, {
|
|
216
259
|
flexDirection: "column",
|
|
217
260
|
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 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 // 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 // Keyboard handling (only active when raw mode is supported)\n useInput(\n (input, key) => {\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 // 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 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":["App","isMac","process","platform","AppContent","store","exit","useApp","isRawModeSupported","useStdin","stdout","useStdout","terminalHeight","rows","allProcesses","useSyncExternalStore","subscribe","getSnapshot","shouldExit","getShouldExit","mode","getMode","selectedIndex","getSelectedIndex","expandedId","getExpandedId","scrollOffset","getScrollOffset","listScrollOffset","getListScrollOffset","errorFooterExpanded","getErrorFooterExpanded","filterMode","getFilterMode","searchTerm","getSearchTerm","isSearching","getIsSearching","_bufferVersion","getBufferVersion","processes","getFilteredProcesses","header","getHeader","showStatusBar","getShowStatusBar","isInteractive","getIsInteractive","expandedHeight","EXPANDED_MAX_VISIBLE_LINES","filterBarHeight","listHintHeight","reservedLines","visibleProcessCount","Math","max","runningCount","getRunningCount","doneCount","getDoneCount","errorCount","getErrorCount","errorLineCount","getErrorLineCount","_isAllComplete","isAllComplete","errorLines","getErrorLines","filterLabels","all","running","finished","failed","useEffect","setMode","clampListViewport","useInput","input","key","escape","cancelSearch","return","confirmSearch","backspace","delete","updateSearchTerm","slice","ctrl","meta","toggleErrorFooter","baseReserved","visibleWhenExpanded","visibleWhenCollapsed","collapse","clearSearch","signalExit","toggleExpand","rightArrow","cycleFilterNext","leftArrow","cycleFilterPrev","startSearch","upArrow","scrollToTop","selectFirst","downArrow","scrollToBottom","selectLast","tab","shift","scrollPageUp","selectPageUp","scrollPageDown","selectPageDown","scrollDown","selectNext","scrollUp","selectPrev","isActive","visibleProcesses","useMemo","showSelection","layoutKey","Box","flexDirection","Text","Divider","dimColor","color","bold","length","map","item","originalIndex","indexOf","CompactProcessLine","isSelected","id","ExpandedOutput","lines","getProcessLines","StatusBar","done","errors","ErrorFooter","isExpanded","StoreContext","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 // Pre-calculate for viewport adjustment\n const baseReserved = (header ? 2 : 0) + (showStatusBar ? 2 : 0);\n const visibleWhenCollapsed = Math.max(1, terminalHeight - baseReserved - 2);\n\n if (input === 'q' || key.escape || key.return) {\n store.exitFullscreen(visibleWhenCollapsed);\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 // Enter - fullscreen view (direct from list or from expanded)\n } else if (key.return) {\n store.enterFullscreen();\n // Space - toggle small expanded preview\n } else if (input === ' ') {\n store.toggleExpand(visibleWhenExpanded, visibleWhenCollapsed);\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":["App","isMac","process","platform","AppContent","store","exit","useApp","isRawModeSupported","useStdin","stdout","useStdout","terminalHeight","rows","allProcesses","useSyncExternalStore","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","EXPANDED_MAX_VISIBLE_LINES","filterBarHeight","listHintHeight","reservedLines","visibleProcessCount","Math","max","runningCount","getRunningCount","doneCount","getDoneCount","errorCount","getErrorCount","errorLineCount","getErrorLineCount","_isAllComplete","isAllComplete","errorLines","getErrorLines","filterLabels","all","running","finished","failed","useEffect","setMode","clampListViewport","fullscreenVisibleLines","useInput","input","key","baseReserved","visibleWhenCollapsed","escape","return","exitFullscreen","meta","upArrow","scrollToTop","downArrow","scrollToBottom","tab","shift","scrollPageUp","scrollPageDown","scrollDown","scrollUp","cancelSearch","confirmSearch","backspace","delete","updateSearchTerm","slice","ctrl","toggleErrorFooter","visibleWhenExpanded","collapse","clearSearch","signalExit","enterFullscreen","toggleExpand","rightArrow","cycleFilterNext","leftArrow","cycleFilterPrev","startSearch","selectFirst","selectLast","selectPageUp","selectPageDown","selectNext","selectPrev","isActive","visibleProcesses","useMemo","showSelection","layoutKey","expandedProcess","getProcess","FullscreenOverlay","title","group","lines","getProcessLines","id","onExit","Box","flexDirection","Text","Divider","dimColor","color","bold","length","map","item","originalIndex","indexOf","CompactProcessLine","isSelected","ExpandedOutput","StatusBar","done","errors","ErrorFooter","isExpanded","StoreContext","Provider","value"],"mappings":";;;;+BA4TA,gDAAgD;AAChD;;;eAAwBA;;;;mBA7TyC;qBACR;2BACd;8BAEd;2EACE;gEACX;oEACI;uEACG;0EACG;kEACR;;;;;;AAEtB,IAAMC,QAAQC,QAAQC,QAAQ,KAAK;AAMnC,SAASC,WAAW,KAAmB;QAAnB,AAAEC,QAAF,MAAEA;IACpB,IAAM,AAAEC,OAASC,IAAAA,WAAM,IAAfD;IACR,IAAM,AAAEE,qBAAuBC,IAAAA,aAAQ,IAA/BD;IACR,IAAM,AAAEE,SAAWC,IAAAA,cAAS,IAApBD;IACR,IAAME,iBAAiBF,CAAAA,mBAAAA,6BAAAA,OAAQG,IAAI,KAAI;IAEvC,2BAA2B;IAC3B,IAAMC,eAAeC,IAAAA,2BAAoB,EAACV,MAAMW,SAAS,EAAEX,MAAMY,WAAW;IAC5E,IAAMC,aAAaH,IAAAA,2BAAoB,EAACV,MAAMW,SAAS,EAAEX,MAAMc,aAAa;IAC5E,IAAMC,OAAOL,IAAAA,2BAAoB,EAACV,MAAMW,SAAS,EAAEX,MAAMgB,OAAO;IAChE,IAAMC,gBAAgBP,IAAAA,2BAAoB,EAACV,MAAMW,SAAS,EAAEX,MAAMkB,gBAAgB;IAClF,IAAMC,aAAaT,IAAAA,2BAAoB,EAACV,MAAMW,SAAS,EAAEX,MAAMoB,aAAa;IAC5E,IAAMC,eAAeX,IAAAA,2BAAoB,EAACV,MAAMW,SAAS,EAAEX,MAAMsB,eAAe;IAChF,IAAMC,mBAAmBb,IAAAA,2BAAoB,EAACV,MAAMW,SAAS,EAAEX,MAAMwB,mBAAmB;IACxF,IAAMC,sBAAsBf,IAAAA,2BAAoB,EAACV,MAAMW,SAAS,EAAEX,MAAM0B,sBAAsB;IAC9F,IAAMC,aAAajB,IAAAA,2BAAoB,EAACV,MAAMW,SAAS,EAAEX,MAAM4B,aAAa;IAC5E,IAAMC,aAAanB,IAAAA,2BAAoB,EAACV,MAAMW,SAAS,EAAEX,MAAM8B,aAAa;IAC5E,IAAMC,cAAcrB,IAAAA,2BAAoB,EAACV,MAAMW,SAAS,EAAEX,MAAMgC,cAAc;IAC9E,IAAMC,eAAevB,IAAAA,2BAAoB,EAACV,MAAMW,SAAS,EAAEX,MAAMkC,eAAe;IAChF,yFAAyF;IACzF,IAAMC,iBAAiBzB,IAAAA,2BAAoB,EAACV,MAAMW,SAAS,EAAEX,MAAMoC,gBAAgB;IAEnF,qCAAqC;IACrC,IAAMC,YAAYrC,MAAMsC,oBAAoB;IAE5C,4CAA4C;IAC5C,IAAMC,SAAS7B,IAAAA,2BAAoB,EAACV,MAAMW,SAAS,EAAEX,MAAMwC,SAAS;IACpE,IAAMC,gBAAgB/B,IAAAA,2BAAoB,EAACV,MAAMW,SAAS,EAAEX,MAAM0C,gBAAgB;IAClF,IAAMC,gBAAgBjC,IAAAA,2BAAoB,EAACV,MAAMW,SAAS,EAAEX,MAAM4C,gBAAgB;IAElF,mGAAmG;IACnG,kGAAkG;IAClG,2FAA2F;IAC3F,IAAMC,iBAAiB1B,aAAa2B,uCAA0B,GAAG,IAAI,GAAG,qBAAqB;IAC7F,IAAMC,kBAAkBhC,SAAS,iBAAiB,CAACI,aAAa,IAAI,GAAG,gCAAgC;IACvG,IAAM6B,iBAAiBjC,SAAS,iBAAiB,CAACI,aAAa,IAAI,GAAG,+BAA+B;IACrG,IAAM8B,gBAAgB,AAACV,CAAAA,SAAS,IAAI,CAAA,IAAME,CAAAA,gBAAgB,IAAI,CAAA,IAAKI,iBAAiBE,kBAAkBC;IACtG,IAAME,sBAAsBC,KAAKC,GAAG,CAAC,GAAG7C,iBAAiB0C;IAEzD,iFAAiF;IACjF,IAAMI,eAAerD,MAAMsD,eAAe;IAC1C,IAAMC,YAAYvD,MAAMwD,YAAY;IACpC,IAAMC,aAAazD,MAAM0D,aAAa;IACtC,IAAMC,iBAAiB3D,MAAM4D,iBAAiB;IAC9C,IAAMC,iBAAiB7D,MAAM8D,aAAa;IAC1C,IAAMC,aAAa/D,MAAMgE,aAAa;IAEtC,6BAA6B;IAC7B,IAAMC,eAAuC;QAC3CC,KAAK;QACLC,SAAS;QACTC,UAAU;QACVC,QAAQ;IACV;IAEA,qBAAqB;IACrBC,IAAAA,gBAAS,EAAC;QACR,IAAIzD,YAAY;YACdZ;QACF;IACF,GAAG;QAACY;QAAYZ;KAAK;IAErB,uEAAuE;IACvE,8DAA8D;IAC9DqE,IAAAA,gBAAS,EAAC;QACR,IAAI3B,iBAAiB5B,SAAS,UAAU;YACtCf,MAAMuE,OAAO,CAAC;QAChB;IACF,GAAG;QAAC5B;QAAe5B;QAAMf;KAAM;IAE/B,sDAAsD;IACtD,0DAA0D;IAC1DsE,IAAAA,gBAAS,EAAC;QACR,IAAIvD,SAAS,iBAAiB,CAACI,YAAY;YACzCnB,MAAMwE,iBAAiB,CAACtB;QAC1B;IACF,GAAG;QAACnC;QAAMI;QAAY+B;QAAqBlD;KAAM;IAEjD,+EAA+E;IAC/E,IAAMyE,yBAAyBtB,KAAKC,GAAG,CAAC,GAAG7C,iBAAiB,IAAI,gCAAgC;IAEhG,6DAA6D;IAC7DmE,IAAAA,aAAQ,EACN,SAACC,OAAOC;QACN,iCAAiC;QACjC,IAAI3C,cAAc;YAChB,wCAAwC;YACxC,IAAM4C,eAAe,AAACtC,CAAAA,SAAS,IAAI,CAAA,IAAME,CAAAA,gBAAgB,IAAI,CAAA;YAC7D,IAAMqC,uBAAuB3B,KAAKC,GAAG,CAAC,GAAG7C,iBAAiBsE,eAAe;YAEzE,IAAIF,UAAU,OAAOC,IAAIG,MAAM,IAAIH,IAAII,MAAM,EAAE;gBAC7ChF,MAAMiF,cAAc,CAACH;YACvB,OAAO,IAAI,AAACF,IAAIM,IAAI,IAAIN,IAAIO,OAAO,IAAKR,UAAU,KAAK;gBACrD3E,MAAMoF,WAAW;YACnB,OAAO,IAAI,AAACR,IAAIM,IAAI,IAAIN,IAAIS,SAAS,IAAKV,UAAU,KAAK;gBACvD3E,MAAMsF,cAAc,CAACb;YACvB,OAAO,IAAIG,IAAIW,GAAG,IAAIX,IAAIY,KAAK,EAAE;gBAC/BxF,MAAMyF,YAAY,CAAChB;YACrB,OAAO,IAAIG,IAAIW,GAAG,IAAI,CAACX,IAAIY,KAAK,EAAE;gBAChCxF,MAAM0F,cAAc,CAACjB;YACvB,OAAO,IAAIG,IAAIS,SAAS,IAAIV,UAAU,KAAK;gBACzC3E,MAAM2F,UAAU,CAAClB;YACnB,OAAO,IAAIG,IAAIO,OAAO,IAAIR,UAAU,KAAK;gBACvC3E,MAAM4F,QAAQ;YAChB;YACA;QACF;QAEA,6BAA6B;QAC7B,IAAI7D,aAAa;YACf,IAAI6C,IAAIG,MAAM,EAAE;gBACd/E,MAAM6F,YAAY;YACpB,OAAO,IAAIjB,IAAII,MAAM,EAAE;gBACrBhF,MAAM8F,aAAa;YACrB,OAAO,IAAIlB,IAAImB,SAAS,IAAInB,IAAIoB,MAAM,EAAE;gBACtChG,MAAMiG,gBAAgB,CAACpE,WAAWqE,KAAK,CAAC,GAAG,CAAC;YAC9C,OAAO,IAAIvB,SAAS,CAACC,IAAIuB,IAAI,IAAI,CAACvB,IAAIM,IAAI,EAAE;gBAC1ClF,MAAMiG,gBAAgB,CAACpE,aAAa8C;YACtC;YACA;QACF;QAEA,IAAI5D,SAAS,UAAU;YACrB,oDAAoD;YACpD,IAAI4D,UAAU,OAAOlB,aAAa,GAAG;gBACnCzD,MAAMoG,iBAAiB;YACzB;QACF,OAAO,IAAIrF,SAAS,eAAe;YACjC,+DAA+D;YAC/D,IAAM8D,gBAAe,AAACtC,CAAAA,SAAS,IAAI,CAAA,IAAME,CAAAA,gBAAgB,IAAI,CAAA;YAC7D,IAAM4D,sBAAsBlD,KAAKC,GAAG,CAAC,GAAG7C,iBAAiBsE,gBAAe/B,uCAA0B,GAAG;YACrG,IAAMgC,wBAAuB3B,KAAKC,GAAG,CAAC,GAAG7C,iBAAiBsE,gBAAe,IAAI,gCAAgC;YAE7G,IAAIF,UAAU,OAAOC,IAAIG,MAAM,EAAE;gBAC/B,IAAI5D,YAAY;oBACdnB,MAAMsG,QAAQ,CAACxB;gBACjB,OAAO,IAAIjD,YAAY;oBACrB,oCAAoC;oBACpC7B,MAAMuG,WAAW;gBACnB,OAAO;oBACLvG,MAAMwG,UAAU,CAAC,YAAO;gBAC1B;YACA,8DAA8D;YAChE,OAAO,IAAI5B,IAAII,MAAM,EAAE;gBACrBhF,MAAMyG,eAAe;YACrB,wCAAwC;YAC1C,OAAO,IAAI9B,UAAU,KAAK;gBACxB3E,MAAM0G,YAAY,CAACL,qBAAqBvB;YACxC,qCAAqC;YACvC,OAAO,IAAIF,IAAI+B,UAAU,IAAI,CAACxF,YAAY;gBACxCnB,MAAM4G,eAAe;YACvB,OAAO,IAAIhC,IAAIiC,SAAS,IAAI,CAAC1F,YAAY;gBACvCnB,MAAM8G,eAAe;YACrB,+BAA+B;YACjC,OAAO,IAAInC,UAAU,OAAO,CAACxD,YAAY;gBACvCnB,MAAM+G,WAAW;YACjB,oDAAoD;YACpD,2CAA2C;YAC7C,OAAO,IAAI,AAACnC,IAAIM,IAAI,IAAIN,IAAIO,OAAO,IAAKR,UAAU,KAAK;gBACrD,IAAIxD,YAAY;oBACdnB,MAAMoF,WAAW;gBACnB,OAAO;oBACLpF,MAAMgH,WAAW,CAAC9D;gBACpB;YACA,uDAAuD;YACzD,OAAO,IAAI,AAAC0B,IAAIM,IAAI,IAAIN,IAAIS,SAAS,IAAKV,UAAU,KAAK;gBACvD,IAAIxD,YAAY;oBACdnB,MAAMsF,cAAc,CAACxC,uCAA0B;gBACjD,OAAO;oBACL9C,MAAMiH,UAAU,CAAC/D;gBACnB;YACA,uEAAuE;YACzE,OAAO,IAAI0B,IAAIW,GAAG,IAAIX,IAAIY,KAAK,EAAE;gBAC/B,IAAIrE,YAAY;oBACdnB,MAAMyF,YAAY,CAAC3C,uCAA0B;gBAC/C,OAAO;oBACL9C,MAAMkH,YAAY,CAACpE,uCAA0B,EAAEI;gBACjD;YACF,OAAO,IAAI0B,IAAIW,GAAG,IAAI,CAACX,IAAIY,KAAK,EAAE;gBAChC,IAAIrE,YAAY;oBACdnB,MAAM0F,cAAc,CAAC5C,uCAA0B;gBACjD,OAAO;oBACL9C,MAAMmH,cAAc,CAACrE,uCAA0B,EAAEI;gBACnD;YACA,sCAAsC;YACxC,OAAO,IAAI0B,IAAIS,SAAS,IAAIV,UAAU,KAAK;gBACzC,IAAIxD,YAAY;oBACdnB,MAAM2F,UAAU,CAAC7C,uCAA0B;gBAC7C,OAAO;oBACL9C,MAAMoH,UAAU,CAAClE;gBACnB;YACF,OAAO,IAAI0B,IAAIO,OAAO,IAAIR,UAAU,KAAK;gBACvC,IAAIxD,YAAY;oBACdnB,MAAM4F,QAAQ;gBAChB,OAAO;oBACL5F,MAAMqH,UAAU,CAACnE;gBACnB;YACF;QACF;IACF,GACA;QAAEoE,UAAUnH,uBAAuB;IAAK;IAG1C,0DAA0D;IAC1D,IAAMoH,mBAAmBC,IAAAA,cAAO,EAAC;QAC/B,IAAIzG,SAAS,eAAe;YAC1B,OAAOsB,UAAU6D,KAAK,CAAC3E,kBAAkBA,mBAAmB2B;QAC9D;QACA,OAAOb;IACT,GAAG;QAACA;QAAWtB;QAAMQ;QAAkB2B;KAAoB;IAE3D,kEAAkE;IAClE,IAAMuE,gBAAgB1G,SAAS;IAE/B,qDAAqD;IACrD,2FAA2F;IAC3F,IAAM2G,YAAY,AAAC,GAAsBvG,OAApBI,kBAAiB,KAAiBkC,OAAdtC,YAAW,KAAiBM,OAAdgC,YAAW,KAA0B9B,OAAvBF,qBAAoB,KAAiBI,OAAdF,YAAW,KAAiBI,OAAdF,YAAW,KAAe,OAAZE;IAExH,2CAA2C;IAC3C,IAAM4F,kBAAkBxG,aAAanB,MAAM4H,UAAU,CAACzG,cAAc;IAEpE,wCAAwC;IACxC,IAAIc,gBAAgB0F,iBAAiB;QACnC,qBAAO,qBAACE,4BAAiB;YAACC,OAAOH,gBAAgBI,KAAK,IAAIJ,gBAAgBG,KAAK;YAAEE,OAAOhI,MAAMiI,eAAe,CAACN,gBAAgBO,EAAE;YAAG7G,cAAcA;YAAc8G,QAAQ;uBAAMnI,MAAMiF,cAAc;;;IACnM;IAEA,qBACE,sBAACmD,QAAG;QAAiBC,eAAc;;YAEhC9F,wBACC;;kCACE,qBAAC+F,SAAI;kCAAE/F;;kCACP,qBAACgG,kBAAO;;;YAKXxH,SAAS,iBAAiB,CAACI,4BAC1B,sBAACiH,QAAG;;kCACF,qBAACE,SAAI;wBAACE,QAAQ;kCAAC;;kCACf,qBAACF,SAAI;wBAACG,OAAO9G,eAAe,YAAY,WAAWA,eAAe,WAAW,QAAQA,eAAe,aAAa,UAAU;wBAAQ+G,IAAI;kCACpIzE,YAAY,CAACtC,WAAW;;kCAE3B,qBAAC2G,SAAI;wBAACE,QAAQ;kCAAC;;oBACdzG,4BACC,sBAACuG,SAAI;;4BACF;0CACD,qBAACA,SAAI;gCAACE,QAAQ;0CAAC;;0CACf,qBAACF,SAAI;0CAAEzG;;0CACP,qBAACyG,SAAI;gCAACE,QAAQ;0CAAC;;;yBAEf3G,2BACF,sBAACyG,SAAI;wBAACE,QAAQ;;4BAAC;4BAAG3G;4BAAW;;uCAE7B,qBAACyG,SAAI;wBAACE,QAAQ;kCAAC;;oBAEhBnG,UAAUsG,MAAM,KAAKlI,aAAakI,MAAM,kBACvC,sBAACL,SAAI;wBAACE,QAAQ;;4BACX;4BAAI;4BACHnG,UAAUsG,MAAM;4BAAC;4BAAElI,aAAakI,MAAM;4BAAC;;;;;0BAOjD,sBAACP,QAAG;gBAACC,eAAc;;oBAChBd,iBAAiBqB,GAAG,CAAC,SAACC;wBACrB,IAAMC,gBAAgBzG,UAAU0G,OAAO,CAACF;wBACxC,qBACE,sBAACT,QAAG;4BAAeC,eAAc;;8CAC/B,qBAACW,6BAAkB;oCAACH,MAAMA;oCAAMI,YAAYxB,iBAAiBqB,kBAAkB7H;;gCAC9EE,eAAe0H,KAAKX,EAAE,kBAAI,qBAACgB,yBAAc;oCAAClB,OAAOhI,MAAMiI,eAAe,CAACY,KAAKX,EAAE;oCAAG7G,cAAcA;;;2BAFxFwH,KAAKX,EAAE;oBAKrB;oBAECnH,SAAS,iBAAiB,CAACI,cAAckB,UAAUsG,MAAM,GAAGzF,qCAC3D,sBAACoF,SAAI;wBAACE,QAAQ;;4BAAC;4BACVnG,UAAUsG,MAAM,GAAGzF;4BAAoB;4BAAuBtD,QAAQ,SAAS;4BAAM;;;;;YAM7F6C,iBAAiBJ,UAAUsG,MAAM,GAAG,mBACnC;;kCACE,qBAACJ,kBAAO;kCACR,qBAACY,oBAAS;wBAAChF,SAASd;wBAAc+F,MAAM7F;wBAAW8F,QAAQ5F;wBAAYM,YAAYJ;;;;YAKtF,CAAChB,iBAAiBc,aAAa,mBAAK,qBAAC6F,sBAAW;gBAACD,QAAQtF;gBAAYwF,YAAY9H;;;OAlE1EiG;AAqEd;AAGe,SAAS/H,IAAI,KAAmB;QAAnB,AAAEK,QAAF,MAAEA;IAC5B,qBACE,qBAACwJ,4BAAY,CAACC,QAAQ;QAACC,OAAO1J;kBAC5B,cAAA,qBAACD;YAAWC,OAAOA;;;AAGzB"}
|
|
@@ -40,15 +40,18 @@ var _default = /*#__PURE__*/ (0, _react.memo)(function ExpandedOutput(param) {
|
|
|
40
40
|
]
|
|
41
41
|
}, scrollOffset + i));
|
|
42
42
|
}),
|
|
43
|
-
hasMore
|
|
43
|
+
hasMore ? /*#__PURE__*/ (0, _jsxruntime.jsxs)(_ink.Text, {
|
|
44
44
|
dimColor: true,
|
|
45
45
|
children: [
|
|
46
46
|
"│ [+",
|
|
47
47
|
remaining,
|
|
48
48
|
" more, Tab/⇧Tab page, ",
|
|
49
49
|
isMac ? '⌥↑/↓' : 'g/G',
|
|
50
|
-
" top/bottom]"
|
|
50
|
+
" top/bottom, ↵ fullscreen]"
|
|
51
51
|
]
|
|
52
|
+
}) : /*#__PURE__*/ (0, _jsxruntime.jsx)(_ink.Text, {
|
|
53
|
+
dimColor: true,
|
|
54
|
+
children: "│ [↵ fullscreen]"
|
|
52
55
|
})
|
|
53
56
|
]
|
|
54
57
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/node/spawn-term/src/components/ExpandedOutput.tsx"],"sourcesContent":["import { Box, Text } from 'ink';\nimport { memo } from 'react';\nimport { EXPANDED_MAX_VISIBLE_LINES } from '../constants.ts';\nimport type { Line } from '../types.ts';\n\nconst isMac = process.platform === 'darwin';\n\ntype Props = {\n lines: Line[];\n scrollOffset: number;\n maxVisible?: number;\n};\n\nexport default memo(function ExpandedOutput({ lines, scrollOffset, maxVisible = EXPANDED_MAX_VISIBLE_LINES }: Props) {\n const visibleLines = lines.slice(scrollOffset, scrollOffset + maxVisible);\n const hasMore = lines.length > scrollOffset + maxVisible;\n const remaining = lines.length - scrollOffset - maxVisible;\n\n if (lines.length === 0) {\n return (\n <Box paddingLeft={2}>\n <Text dimColor>│ (no output)</Text>\n </Box>\n );\n }\n\n return (\n <Box flexDirection=\"column\" paddingLeft={2}>\n {visibleLines.map((line, i) => (\n // biome-ignore lint/suspicious/noArrayIndexKey: Lines have no unique ID, index is stable for this scrolling view\n <Text key={scrollOffset + i}>│ {line.text}</Text>\n ))}\n {hasMore
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/node/spawn-term/src/components/ExpandedOutput.tsx"],"sourcesContent":["import { Box, Text } from 'ink';\nimport { memo } from 'react';\nimport { EXPANDED_MAX_VISIBLE_LINES } from '../constants.ts';\nimport type { Line } from '../types.ts';\n\nconst isMac = process.platform === 'darwin';\n\ntype Props = {\n lines: Line[];\n scrollOffset: number;\n maxVisible?: number;\n};\n\nexport default memo(function ExpandedOutput({ lines, scrollOffset, maxVisible = EXPANDED_MAX_VISIBLE_LINES }: Props) {\n const visibleLines = lines.slice(scrollOffset, scrollOffset + maxVisible);\n const hasMore = lines.length > scrollOffset + maxVisible;\n const remaining = lines.length - scrollOffset - maxVisible;\n\n if (lines.length === 0) {\n return (\n <Box paddingLeft={2}>\n <Text dimColor>│ (no output)</Text>\n </Box>\n );\n }\n\n return (\n <Box flexDirection=\"column\" paddingLeft={2}>\n {visibleLines.map((line, i) => (\n // biome-ignore lint/suspicious/noArrayIndexKey: Lines have no unique ID, index is stable for this scrolling view\n <Text key={scrollOffset + i}>│ {line.text}</Text>\n ))}\n {hasMore ? (\n <Text dimColor>\n │ [+{remaining} more, Tab/⇧Tab page, {isMac ? '⌥↑/↓' : 'g/G'} top/bottom, ↵ fullscreen]\n </Text>\n ) : (\n <Text dimColor>│ [↵ fullscreen]</Text>\n )}\n </Box>\n );\n});\n"],"names":["isMac","process","platform","memo","ExpandedOutput","lines","scrollOffset","maxVisible","EXPANDED_MAX_VISIBLE_LINES","visibleLines","slice","hasMore","length","remaining","Box","paddingLeft","Text","dimColor","flexDirection","map","line","i","text"],"mappings":";;;;+BAaA;;;eAAA;;;;mBAb0B;qBACL;2BACsB;AAG3C,IAAMA,QAAQC,QAAQC,QAAQ,KAAK;IAQnC,yBAAeC,IAAAA,WAAI,EAAC,SAASC,eAAe,KAAuE;QAArEC,QAAF,MAAEA,OAAOC,eAAT,MAASA,kCAAT,MAAuBC,YAAAA,4CAAaC,uCAA0B;IACxG,IAAMC,eAAeJ,MAAMK,KAAK,CAACJ,cAAcA,eAAeC;IAC9D,IAAMI,UAAUN,MAAMO,MAAM,GAAGN,eAAeC;IAC9C,IAAMM,YAAYR,MAAMO,MAAM,GAAGN,eAAeC;IAEhD,IAAIF,MAAMO,MAAM,KAAK,GAAG;QACtB,qBACE,qBAACE,QAAG;YAACC,aAAa;sBAChB,cAAA,qBAACC,SAAI;gBAACC,QAAQ;0BAAC;;;IAGrB;IAEA,qBACE,sBAACH,QAAG;QAACI,eAAc;QAASH,aAAa;;YACtCN,aAAaU,GAAG,CAAC,SAACC,MAAMC;uBACvB,iHAAiH;8BACjH,sBAACL,SAAI;;wBAAwB;wBAAGI,KAAKE,IAAI;;mBAA9BhB,eAAee;;YAE3BV,wBACC,sBAACK,SAAI;gBAACC,QAAQ;;oBAAC;oBACRJ;oBAAU;oBAAuBb,QAAQ,SAAS;oBAAM;;+BAG/D,qBAACgB,SAAI;gBAACC,QAAQ;0BAAC;;;;AAIvB"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
Object.defineProperty(exports, "default", {
|
|
6
|
+
enumerable: true,
|
|
7
|
+
get: function() {
|
|
8
|
+
return _default;
|
|
9
|
+
}
|
|
10
|
+
});
|
|
11
|
+
var _jsxruntime = require("react/jsx-runtime");
|
|
12
|
+
var _ink = require("ink");
|
|
13
|
+
var _react = require("react");
|
|
14
|
+
var isMac = process.platform === 'darwin';
|
|
15
|
+
// ANSI escape codes for alternate screen buffer
|
|
16
|
+
var ENTER_ALT_SCREEN = '\x1b[?1049h';
|
|
17
|
+
var EXIT_ALT_SCREEN = '\x1b[?1049l';
|
|
18
|
+
var CLEAR_SCREEN = '\x1b[2J';
|
|
19
|
+
var CURSOR_HOME = '\x1b[H';
|
|
20
|
+
var _default = /*#__PURE__*/ (0, _react.memo)(function FullscreenOverlay(param) {
|
|
21
|
+
var title = param.title, lines = param.lines, scrollOffset = param.scrollOffset;
|
|
22
|
+
var stdout = (0, _ink.useStdout)().stdout;
|
|
23
|
+
var terminalHeight = (stdout === null || stdout === void 0 ? void 0 : stdout.rows) || 24;
|
|
24
|
+
// Reserve lines for header (title + divider) and footer (scroll hint)
|
|
25
|
+
var headerLines = 2;
|
|
26
|
+
var footerLines = 1;
|
|
27
|
+
var maxVisible = Math.max(1, terminalHeight - headerLines - footerLines);
|
|
28
|
+
// Enter alternate screen on mount, exit on unmount
|
|
29
|
+
(0, _react.useEffect)(function() {
|
|
30
|
+
if (stdout) {
|
|
31
|
+
stdout.write(ENTER_ALT_SCREEN + CLEAR_SCREEN + CURSOR_HOME);
|
|
32
|
+
}
|
|
33
|
+
return function() {
|
|
34
|
+
if (stdout) {
|
|
35
|
+
stdout.write(EXIT_ALT_SCREEN);
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
}, [
|
|
39
|
+
stdout
|
|
40
|
+
]);
|
|
41
|
+
var visibleLines = lines.slice(scrollOffset, scrollOffset + maxVisible);
|
|
42
|
+
var totalLines = lines.length;
|
|
43
|
+
var currentLine = scrollOffset + 1;
|
|
44
|
+
var endLine = Math.min(scrollOffset + maxVisible, totalLines);
|
|
45
|
+
return /*#__PURE__*/ (0, _jsxruntime.jsxs)(_ink.Box, {
|
|
46
|
+
flexDirection: "column",
|
|
47
|
+
height: terminalHeight,
|
|
48
|
+
children: [
|
|
49
|
+
/*#__PURE__*/ (0, _jsxruntime.jsx)(_ink.Text, {
|
|
50
|
+
bold: true,
|
|
51
|
+
color: "cyan",
|
|
52
|
+
children: title
|
|
53
|
+
}),
|
|
54
|
+
/*#__PURE__*/ (0, _jsxruntime.jsx)(_ink.Text, {
|
|
55
|
+
dimColor: true,
|
|
56
|
+
children: '─'.repeat(Math.min(80, (stdout === null || stdout === void 0 ? void 0 : stdout.columns) || 80))
|
|
57
|
+
}),
|
|
58
|
+
/*#__PURE__*/ (0, _jsxruntime.jsx)(_ink.Box, {
|
|
59
|
+
flexDirection: "column",
|
|
60
|
+
flexGrow: 1,
|
|
61
|
+
children: lines.length === 0 ? /*#__PURE__*/ (0, _jsxruntime.jsx)(_ink.Text, {
|
|
62
|
+
dimColor: true,
|
|
63
|
+
children: "(no output)"
|
|
64
|
+
}) : visibleLines.map(function(line, i) {
|
|
65
|
+
return(// biome-ignore lint/suspicious/noArrayIndexKey: Lines have no unique ID, index is stable for this scrolling view
|
|
66
|
+
/*#__PURE__*/ (0, _jsxruntime.jsx)(_ink.Text, {
|
|
67
|
+
children: line.text
|
|
68
|
+
}, scrollOffset + i));
|
|
69
|
+
})
|
|
70
|
+
}),
|
|
71
|
+
/*#__PURE__*/ (0, _jsxruntime.jsxs)(_ink.Text, {
|
|
72
|
+
dimColor: true,
|
|
73
|
+
children: [
|
|
74
|
+
"Lines ",
|
|
75
|
+
currentLine,
|
|
76
|
+
"-",
|
|
77
|
+
endLine,
|
|
78
|
+
" of ",
|
|
79
|
+
totalLines,
|
|
80
|
+
" | j/k scroll | Tab/⇧Tab page | ",
|
|
81
|
+
isMac ? '⌥↑/↓' : 'g/G',
|
|
82
|
+
" top/bottom | ↵/q exit"
|
|
83
|
+
]
|
|
84
|
+
})
|
|
85
|
+
]
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
/* CJS INTEROP */ if (exports.__esModule && exports.default) { try { Object.defineProperty(exports.default, '__esModule', { value: true }); for (var key in exports) { exports.default[key] = exports[key]; } } catch (_) {}; module.exports = exports.default; }
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/node/spawn-term/src/components/FullscreenOverlay.tsx"],"sourcesContent":["import { Box, Text, useStdout } from 'ink';\nimport { memo, useEffect } from 'react';\nimport type { Line } from '../types.ts';\n\nconst isMac = process.platform === 'darwin';\n\n// ANSI escape codes for alternate screen buffer\nconst ENTER_ALT_SCREEN = '\\x1b[?1049h';\nconst EXIT_ALT_SCREEN = '\\x1b[?1049l';\nconst CLEAR_SCREEN = '\\x1b[2J';\nconst CURSOR_HOME = '\\x1b[H';\n\ntype Props = {\n title: string;\n lines: Line[];\n scrollOffset: number;\n onExit: () => void;\n};\n\nexport default memo(function FullscreenOverlay({ title, lines, scrollOffset }: Props) {\n const { stdout } = useStdout();\n const terminalHeight = stdout?.rows || 24;\n\n // Reserve lines for header (title + divider) and footer (scroll hint)\n const headerLines = 2;\n const footerLines = 1;\n const maxVisible = Math.max(1, terminalHeight - headerLines - footerLines);\n\n // Enter alternate screen on mount, exit on unmount\n useEffect(() => {\n if (stdout) {\n stdout.write(ENTER_ALT_SCREEN + CLEAR_SCREEN + CURSOR_HOME);\n }\n return () => {\n if (stdout) {\n stdout.write(EXIT_ALT_SCREEN);\n }\n };\n }, [stdout]);\n\n const visibleLines = lines.slice(scrollOffset, scrollOffset + maxVisible);\n const totalLines = lines.length;\n const currentLine = scrollOffset + 1;\n const endLine = Math.min(scrollOffset + maxVisible, totalLines);\n\n return (\n <Box flexDirection=\"column\" height={terminalHeight}>\n {/* Header */}\n <Text bold color=\"cyan\">\n {title}\n </Text>\n <Text dimColor>{'─'.repeat(Math.min(80, stdout?.columns || 80))}</Text>\n\n {/* Content */}\n <Box flexDirection=\"column\" flexGrow={1}>\n {lines.length === 0 ? (\n <Text dimColor>(no output)</Text>\n ) : (\n visibleLines.map((line, i) => (\n // biome-ignore lint/suspicious/noArrayIndexKey: Lines have no unique ID, index is stable for this scrolling view\n <Text key={scrollOffset + i}>{line.text}</Text>\n ))\n )}\n </Box>\n\n {/* Footer */}\n <Text dimColor>\n Lines {currentLine}-{endLine} of {totalLines} | j/k scroll | Tab/⇧Tab page | {isMac ? '⌥↑/↓' : 'g/G'} top/bottom | ↵/q exit\n </Text>\n </Box>\n );\n});\n"],"names":["isMac","process","platform","ENTER_ALT_SCREEN","EXIT_ALT_SCREEN","CLEAR_SCREEN","CURSOR_HOME","memo","FullscreenOverlay","title","lines","scrollOffset","stdout","useStdout","terminalHeight","rows","headerLines","footerLines","maxVisible","Math","max","useEffect","write","visibleLines","slice","totalLines","length","currentLine","endLine","min","Box","flexDirection","height","Text","bold","color","dimColor","repeat","columns","flexGrow","map","line","i","text"],"mappings":";;;;+BAmBA;;;eAAA;;;;mBAnBqC;qBACL;AAGhC,IAAMA,QAAQC,QAAQC,QAAQ,KAAK;AAEnC,gDAAgD;AAChD,IAAMC,mBAAmB;AACzB,IAAMC,kBAAkB;AACxB,IAAMC,eAAe;AACrB,IAAMC,cAAc;IASpB,yBAAeC,IAAAA,WAAI,EAAC,SAASC,kBAAkB,KAAqC;QAAnCC,QAAF,MAAEA,OAAOC,QAAT,MAASA,OAAOC,eAAhB,MAAgBA;IAC7D,IAAM,AAAEC,SAAWC,IAAAA,cAAS,IAApBD;IACR,IAAME,iBAAiBF,CAAAA,mBAAAA,6BAAAA,OAAQG,IAAI,KAAI;IAEvC,sEAAsE;IACtE,IAAMC,cAAc;IACpB,IAAMC,cAAc;IACpB,IAAMC,aAAaC,KAAKC,GAAG,CAAC,GAAGN,iBAAiBE,cAAcC;IAE9D,mDAAmD;IACnDI,IAAAA,gBAAS,EAAC;QACR,IAAIT,QAAQ;YACVA,OAAOU,KAAK,CAACnB,mBAAmBE,eAAeC;QACjD;QACA,OAAO;YACL,IAAIM,QAAQ;gBACVA,OAAOU,KAAK,CAAClB;YACf;QACF;IACF,GAAG;QAACQ;KAAO;IAEX,IAAMW,eAAeb,MAAMc,KAAK,CAACb,cAAcA,eAAeO;IAC9D,IAAMO,aAAaf,MAAMgB,MAAM;IAC/B,IAAMC,cAAchB,eAAe;IACnC,IAAMiB,UAAUT,KAAKU,GAAG,CAAClB,eAAeO,YAAYO;IAEpD,qBACE,sBAACK,QAAG;QAACC,eAAc;QAASC,QAAQlB;;0BAElC,qBAACmB,SAAI;gBAACC,IAAI;gBAACC,OAAM;0BACd1B;;0BAEH,qBAACwB,SAAI;gBAACG,QAAQ;0BAAE,IAAIC,MAAM,CAAClB,KAAKU,GAAG,CAAC,IAAIjB,CAAAA,mBAAAA,6BAAAA,OAAQ0B,OAAO,KAAI;;0BAG3D,qBAACR,QAAG;gBAACC,eAAc;gBAASQ,UAAU;0BACnC7B,MAAMgB,MAAM,KAAK,kBAChB,qBAACO,SAAI;oBAACG,QAAQ;8BAAC;qBAEfb,aAAaiB,GAAG,CAAC,SAACC,MAAMC;2BACtB,iHAAiH;kCACjH,qBAACT,SAAI;kCAAyBQ,KAAKE,IAAI;uBAA5BhC,eAAe+B;;;0BAMhC,sBAACT,SAAI;gBAACG,QAAQ;;oBAAC;oBACNT;oBAAY;oBAAEC;oBAAQ;oBAAKH;oBAAW;oBAAiCzB,QAAQ,SAAS;oBAAM;;;;;AAI7G"}
|
|
@@ -12,6 +12,7 @@ export declare class ProcessStore {
|
|
|
12
12
|
private filterMode;
|
|
13
13
|
private searchTerm;
|
|
14
14
|
private isSearching;
|
|
15
|
+
private isFullscreen;
|
|
15
16
|
private header;
|
|
16
17
|
private showStatusBar;
|
|
17
18
|
private isInteractive;
|
|
@@ -49,6 +50,7 @@ export declare class ProcessStore {
|
|
|
49
50
|
getFilterMode: () => FilterMode;
|
|
50
51
|
getSearchTerm: () => string;
|
|
51
52
|
getIsSearching: () => boolean;
|
|
53
|
+
getIsFullscreen: () => boolean;
|
|
52
54
|
getFilteredProcesses: () => ChildProcess[];
|
|
53
55
|
getScrollOffset: () => number;
|
|
54
56
|
getHeader: () => string | undefined;
|
|
@@ -64,6 +66,8 @@ export declare class ProcessStore {
|
|
|
64
66
|
cancelSearch(): void;
|
|
65
67
|
confirmSearch(): void;
|
|
66
68
|
clearSearch(): void;
|
|
69
|
+
enterFullscreen(): void;
|
|
70
|
+
exitFullscreen(visibleCountWhenCollapsed?: number): void;
|
|
67
71
|
toggleErrorFooter(): void;
|
|
68
72
|
expandErrorFooter(): void;
|
|
69
73
|
selectNext(visibleCount?: number): void;
|
|
@@ -116,6 +116,7 @@ var ProcessStore = /*#__PURE__*/ function() {
|
|
|
116
116
|
this.filterMode = 'all';
|
|
117
117
|
this.searchTerm = '';
|
|
118
118
|
this.isSearching = false;
|
|
119
|
+
this.isFullscreen = false;
|
|
119
120
|
this.showStatusBar = false;
|
|
120
121
|
this.isInteractive = false;
|
|
121
122
|
// === INFRASTRUCTURE ===
|
|
@@ -212,6 +213,9 @@ var ProcessStore = /*#__PURE__*/ function() {
|
|
|
212
213
|
this.getIsSearching = function() {
|
|
213
214
|
return _this.isSearching;
|
|
214
215
|
};
|
|
216
|
+
this.getIsFullscreen = function() {
|
|
217
|
+
return _this.isFullscreen;
|
|
218
|
+
};
|
|
215
219
|
// Get processes filtered by current filter mode and search term
|
|
216
220
|
this.getFilteredProcesses = function() {
|
|
217
221
|
var filtered = _this.processes;
|
|
@@ -437,6 +441,29 @@ var ProcessStore = /*#__PURE__*/ function() {
|
|
|
437
441
|
this.listNav.toStart();
|
|
438
442
|
this.notify();
|
|
439
443
|
};
|
|
444
|
+
// Fullscreen mode (alternate screen buffer)
|
|
445
|
+
_proto.enterFullscreen = function enterFullscreen() {
|
|
446
|
+
// If not expanded, expand the selected process first
|
|
447
|
+
if (!this.expandedId) {
|
|
448
|
+
var selected = this.getSelectedProcess();
|
|
449
|
+
if (selected) {
|
|
450
|
+
this.expandedId = selected.id;
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
if (this.expandedId) {
|
|
454
|
+
this.isFullscreen = true;
|
|
455
|
+
this.notify();
|
|
456
|
+
}
|
|
457
|
+
};
|
|
458
|
+
_proto.exitFullscreen = function exitFullscreen(visibleCountWhenCollapsed) {
|
|
459
|
+
this.isFullscreen = false;
|
|
460
|
+
// Also collapse when exiting fullscreen
|
|
461
|
+
this.expandedId = null;
|
|
462
|
+
if (visibleCountWhenCollapsed) {
|
|
463
|
+
this.listNav.clampViewport(visibleCountWhenCollapsed);
|
|
464
|
+
}
|
|
465
|
+
this.notify();
|
|
466
|
+
};
|
|
440
467
|
// Error footer methods (for non-interactive mode)
|
|
441
468
|
_proto.toggleErrorFooter = function toggleErrorFooter() {
|
|
442
469
|
this.errorFooterExpanded = !this.errorFooterExpanded;
|
|
@@ -614,6 +641,7 @@ var ProcessStore = /*#__PURE__*/ function() {
|
|
|
614
641
|
this.filterMode = 'all';
|
|
615
642
|
this.searchTerm = '';
|
|
616
643
|
this.isSearching = false;
|
|
644
|
+
this.isFullscreen = false;
|
|
617
645
|
this.header = undefined;
|
|
618
646
|
};
|
|
619
647
|
// === 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';\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\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\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 // 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.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","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","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","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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"}
|
|
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 not expanded, expand the selected process first\n if (!this.expandedId) {\n const selected = this.getSelectedProcess();\n if (selected) {\n this.expandedId = selected.id;\n }\n }\n if (this.expandedId) {\n this.isFullscreen = true;\n this.notify();\n }\n }\n\n exitFullscreen(visibleCountWhenCollapsed?: number): void {\n this.isFullscreen = false;\n // Also collapse when exiting fullscreen\n this.expandedId = null;\n if (visibleCountWhenCollapsed) {\n this.listNav.clampViewport(visibleCountWhenCollapsed);\n }\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","selected","exitFullscreen","visibleCountWhenCollapsed","clampViewport","toggleErrorFooter","expandErrorFooter","selectNext","visibleCount","down","ensureVisible","selectPrev","up","selectPageDown","pageSize","pageDown","selectPageUp","pageUp","selectFirst","selectLast","toEnd","clampListViewport","changed","getExpandedNav","nav","scrollDown","maxVisible","expanded","maxOffset","scrollUp","scrollPageDown","newPosition","min","scrollPageUp","scrollToTop","scrollToBottom","toggleExpand","visibleCountWhenExpanded","collapse","signalExit","callback","reset","dispose","forEach","l"],"mappings":";;;;+BAYaA;;;eAAAA;;;wBAZa;2BACW;uBAEZ;2BACuB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAMhD,IAAMC,eAA6B;IAAC;IAAO;IAAW;IAAY;CAAS;AAEpE,IAAA,AAAMD,6BAAN;;aAAMA;;YA4BCE,UAAAA,iEAA0B,CAAC;gCA5B5BF;QACX,mCAAmC;aAC3BG,YAA4B,EAAE;aAC9BC,eAAyB,EAAE,EAAE,yBAAyB;QAK9D,qBAAqB;aACbC,OAAa;aACbC,aAA4B;aAC5BC,sBAAsB,OAAO,mCAAmC;aAChEC,aAAyB;aACzBC,aAAa;aACbC,cAAc;aACdC,eAAe;aAIfC,gBAAgB;aAChBC,gBAAgB;QAExB,yBAAyB;aACjBC,YAAY,IAAIC;aAChBC,aAAa;aACbC,eAAoC;aACpCC,gBAAgB,GAAG,qDAAqD;QAgBhF,kDAAkD;aAElDC,YAAY,SAACC;YACX,MAAKN,SAAS,CAACO,GAAG,CAACD;YACnB,OAAO;uBAAM,MAAKN,SAAS,CAACQ,MAAM,CAACF;;QACrC;aAEAG,cAAc;mBAAsB,MAAKpB,SAAS;;QAElD,wBAAwB;aAExBqB,sBAAsB;YACpB,OAAO,MAAKrB,SAAS,CAACsB,MAAM,CAAC,SAACC;uBAAMA,EAAEC,KAAK,KAAK;;QAClD;aAEAC,wBAAwB;YACtB,6BAA6B;YAC7B,OAAO,MAAKxB,YAAY,CAACyB,GAAG,CAAC,SAACC;uBAAOC,IAAAA,mBAAS,EAAC,MAAK5B,SAAS,EAAE,SAACuB;2BAAMA,EAAEI,EAAE,KAAKA;;eAAKL,MAAM,CAAC,SAACC;uBAAyBA,MAAMM;;QAC7H;aAEAC,qBAAqB;YACnB,OAAO,MAAK9B,SAAS,CAACsB,MAAM,CAAC,SAACC;uBAAMA,EAAEC,KAAK,KAAK;;QAClD;QAEA,SAAS;aACTO,kBAAkB;mBAAc,MAAK/B,SAAS,CAACsB,MAAM,CAAC,SAACC;uBAAMA,EAAEC,KAAK,KAAK;eAAWQ,MAAM;;aAC1FC,oBAAoB;gBAEXC;YADP,IAAI,MAAKlC,SAAS,CAACgC,MAAM,KAAK,GAAG,OAAOG,iCAAoB;YAC5D,OAAOD,CAAAA,QAAAA,MAAKE,GAAG,OAARF,OAAS,qBAAG,MAAKlC,SAAS,CAAC0B,GAAG,CAAC,SAACH;uBAAM,AAACA,CAAAA,EAAEc,KAAK,IAAId,EAAEe,KAAK,AAAD,EAAGN,MAAM;;QAC1E;aACAO,eAAe;mBAAc,MAAKvC,SAAS,CAACsB,MAAM,CAAC,SAACC;uBAAMA,EAAEC,KAAK,KAAK;eAAWQ,MAAM;;aACvFQ,gBAAgB;mBAAc,MAAKxC,SAAS,CAACsB,MAAM,CAAC,SAACC;uBAAMA,EAAEC,KAAK,KAAK;eAASQ,MAAM;;aACtFS,oBAAoB;YAClB,OAAO,MAAKzC,SAAS,CAACsB,MAAM,CAAC,SAACC;uBAAMA,EAAEC,KAAK,KAAK;eAASkB,MAAM,CAAC,SAACC,OAAOpB;uBAAMoB,QAAQ,MAAKC,mBAAmB,CAACrB,EAAEI,EAAE;eAAG;QACxH;QA+EA,8BAA8B;aAE9BkB,UAAU;mBAAY,MAAK3C,IAAI;;aAC/B4C,mBAAmB;mBAAc,MAAKC,OAAO,CAACC,QAAQ;;aACtDC,gBAAgB;mBAAqB,MAAK9C,UAAU;;aACpD+C,sBAAsB;mBAAc,MAAKH,OAAO,CAACI,cAAc;;aAC/DC,yBAAyB;mBAAe,MAAKhD,mBAAmB;;aAChEiD,mBAAmB;mBAAc,MAAKtC,aAAa;;aACnDuC,gBAAgB;mBAAkB,MAAKjD,UAAU;;aACjDkD,gBAAgB;mBAAc,MAAKjD,UAAU;;aAC7CkD,iBAAiB;mBAAe,MAAKjD,WAAW;;aAChDkD,kBAAkB;mBAAe,MAAKjD,YAAY;;QAElD,gEAAgE;aAChEkD,uBAAuB;YACrB,IAAIC,WAAW,MAAK3D,SAAS;YAE7B,oBAAoB;YACpB,OAAQ,MAAKK,UAAU;gBACrB,KAAK;oBACHsD,WAAWA,SAASrC,MAAM,CAAC,SAACC;+BAAMA,EAAEC,KAAK,KAAK;;oBAC9C;gBACF,KAAK;oBACHmC,WAAWA,SAASrC,MAAM,CAAC,SAACC;+BAAMA,EAAEC,KAAK,KAAK;;oBAC9C;gBACF,KAAK;oBACHmC,WAAWA,SAASrC,MAAM,CAAC,SAACC;+BAAMA,EAAEC,KAAK,KAAK;;oBAC9C;YACJ;YAEA,oBAAoB;YACpB,IAAI,MAAKlB,UAAU,EAAE;gBACnB,IAAMsD,OAAO,MAAKtD,UAAU,CAACuD,WAAW;gBACxCF,WAAWA,SAASrC,MAAM,CAAC,SAACC;2BAAMA,EAAEe,KAAK,CAACuB,WAAW,GAAGC,QAAQ,CAACF,SAAUrC,EAAEc,KAAK,IAAId,EAAEc,KAAK,CAACwB,WAAW,GAAGC,QAAQ,CAACF;;YACvH;YAEA,OAAOD;QACT;QAEA,wDAAwD;aACxDI,kBAAkB;gBAGTC;YAFP,IAAI,CAAC,MAAK7D,UAAU,EAAE,OAAO;YAC7B,IAAM6D,UAAU,MAAKC,UAAU,CAAC,MAAK9D,UAAU;gBACxC6D;YAAP,OAAOA,CAAAA,8BAAAA,oBAAAA,+BAAAA,qBAAAA,QAASE,SAAS,cAAlBF,yCAAAA,mBAAoBhB,QAAQ,cAA5BgB,yCAAAA,8BAAgC;QACzC;QAEA,6DAA6D;aAC7DG,YAAY;mBAA0B,MAAKC,MAAM;;aACjDC,mBAAmB;mBAAe,MAAK5D,aAAa;;aACpD6D,mBAAmB;mBAAe,MAAK5D,aAAa;;aACpD6D,gBAAgB;mBAAe,MAAKvE,SAAS,CAACgC,MAAM,GAAG,KAAK,MAAKhC,SAAS,CAACwE,KAAK,CAAC,SAACjD;uBAAMA,EAAEC,KAAK,KAAK;;;aA0QpGiD,gBAAgB;mBAAe,MAAK5D,UAAU;;aAC9C6D,kBAAkB;mBAA2B,MAAK5D,YAAY;;QA3b5D,IAAI,CAACsD,MAAM,GAAGrE,QAAQqE,MAAM;YACPrE;QAArB,IAAI,CAACU,aAAa,GAAGV,CAAAA,yBAAAA,QAAQU,aAAa,cAArBV,oCAAAA,yBAAyB;YACzBA;QAArB,IAAI,CAACW,aAAa,GAAGX,CAAAA,uBAAAA,QAAQ4E,WAAW,cAAnB5E,kCAAAA,uBAAuB;QAE5C,kDAAkD;QAClD,0EAA0E;QAC1E,IAAI,CAACgD,OAAO,GAAG6B,IAAAA,4BAAe,EAAC;YAC7BC,WAAW;uBAAM,MAAKnB,oBAAoB,GAAG1B,MAAM;;YACnD8C,MAAM;YACNC,QAAQ;uBAAM,MAAKC,MAAM;;QAC3B;;iBAvCSnF;IA8EXoF,OAAAA,aAKC,GALDA,SAAAA;;QACE,OAAO,IAAI,CAACnD,kBAAkB,GAAGJ,GAAG,CAAC,SAACH;mBAAO;gBAC3C2D,aAAa3D,EAAEc,KAAK,IAAId,EAAEe,KAAK;gBAC/B6C,OAAO,MAAKC,eAAe,CAAC7D,EAAEI,EAAE;YAClC;;IACF;IAEA,0BAA0B;IAE1B0D,OAAAA,UAYC,GAZDA,SAAAA,WAAWrB,OAAqB;;QAC9B,2CAA2C;QAC3C,IAAMsB,iBAA+B,wCAChCtB;YACHE,WAAWU,IAAAA,4BAAe,EAAC;gBACzBC,WAAW;2BAAM,MAAKjC,mBAAmB,CAAC0C,eAAe3D,EAAE;;gBAC3DmD,MAAM;gBACNC,QAAQ;2BAAM,MAAKC,MAAM;;YAC3B;;QAEF,IAAI,CAAChF,SAAS,GAAG,AAAC,qBAAG,IAAI,CAACA,SAAS,SAAlB;YAAoBsF;SAAe;QACpD,IAAI,CAACN,MAAM;IACb;IAEAO,OAAAA,aAkBC,GAlBDA,SAAAA,cAAc5D,EAAU,EAAE6D,MAA6B;QACrD,IAAMC,aAAa7D,IAAAA,mBAAS,EAAC,IAAI,CAAC5B,SAAS,EAAE,SAACuB;mBAAMA,EAAEI,EAAE,KAAKA;;QAC7D,IAAM+D,aAAaD,CAAAA,uBAAAA,iCAAAA,WAAYjE,KAAK,MAAK;QACzC,IAAMmE,gBAAgBH,OAAOhE,KAAK,IAAIgE,OAAOhE,KAAK,KAAK;QAEvD,IAAI,CAACxB,SAAS,GAAG,IAAI,CAACA,SAAS,CAAC0B,GAAG,CAAC,SAACH;mBAAOA,EAAEI,EAAE,KAAKA,KAAK,mBAAKJ,GAAMiE,UAAWjE;;QAEhF,yBAAyB;QACzB,IAAImE,cAAcC,iBAAiB,CAAC,IAAI,CAAC1F,YAAY,CAAC6D,QAAQ,CAACnC,KAAK;YAClE,IAAI,CAAC1B,YAAY,GAAG,AAAC,qBAAG,IAAI,CAACA,YAAY,SAArB;gBAAuB0B;aAAG;QAChD;QAEA,gFAAgF;QAChF,IAAI,CAAC,IAAI,CAACjB,aAAa,IAAI,IAAI,CAAC6D,aAAa,MAAM,IAAI,CAAC/B,aAAa,KAAK,GAAG;YAC3E,IAAI,CAACpC,mBAAmB,GAAG;QAC7B;QAEA,IAAI,CAAC4E,MAAM;IACb;IAEAY,OAAAA,WAKC,GALDA,SAAAA,YAAYjE,EAAU,EAAEkE,QAAgB;QACtC,IAAM7B,UAAUpC,IAAAA,mBAAS,EAAC,IAAI,CAAC5B,SAAS,EAAE,SAACuB;mBAAMA,EAAEI,EAAE,KAAKA;;QAC1D,IAAIqC,SAAS;YACX,IAAI,CAACuB,aAAa,CAAC5D,IAAI;gBAAEwD,OAAOnB,QAAQmB,KAAK,CAACW,MAAM,CAACD;YAAU;QACjE;IACF;IAEA5B,OAAAA,UAEC,GAFDA,SAAAA,WAAWtC,EAAU;QACnB,OAAOC,IAAAA,mBAAS,EAAC,IAAI,CAAC5B,SAAS,EAAE,SAACuB;mBAAMA,EAAEI,EAAE,KAAKA;;IACnD;IAEA,qEAAqE;IACrEyD,OAAAA,eAUC,GAVDA,SAAAA,gBAAgBzD,EAAU;QACxB,IAAMqC,UAAU,IAAI,CAACC,UAAU,CAACtC;QAChC,IAAI,CAACqC,SAAS,OAAO,EAAE;QACvB,IAAIA,QAAQ+B,cAAc,EAAE;YAC1B,OAAO/B,QAAQ+B,cAAc,CAACC,QAAQ,GAAGtE,GAAG,CAAC,SAACuE;uBAAU;oBACtDC,MAAMC,iBAAQ,CAACC,MAAM;oBACrBH,MAAAA;gBACF;;QACF;QACA,OAAOjC,QAAQmB,KAAK;IACtB;IAEA,qDAAqD;IACrDvC,OAAAA,mBAOC,GAPDA,SAAAA,oBAAoBjB,EAAU;QAC5B,IAAMqC,UAAU,IAAI,CAACC,UAAU,CAACtC;QAChC,IAAI,CAACqC,SAAS,OAAO;QACrB,IAAIA,QAAQ+B,cAAc,EAAE;YAC1B,OAAO/B,QAAQ+B,cAAc,CAACM,SAAS;QACzC;QACA,OAAOrC,QAAQmB,KAAK,CAACnD,MAAM;IAC7B;IAsDA,gCAAgC;IAEhCsE,OAAAA,OAMC,GANDA,SAAAA,QAAQpG,IAAU;QAChB,IAAI,CAACA,IAAI,GAAGA;QACZ,IAAIA,SAAS,eAAe;YAC1B,IAAI,CAAC6C,OAAO,CAACwD,WAAW,CAAC;QAC3B;QACA,IAAI,CAACvB,MAAM;IACb;IAEAwB,OAAAA,kBAEC,GAFDA,SAAAA;QACE,OAAO,IAAI,CAAC9C,oBAAoB,EAAE,CAAC,IAAI,CAACX,OAAO,CAACC,QAAQ,CAAC;IAC3D;IAEA,0CAA0C;IAC1CyD,OAAAA,eAQC,GARDA,SAAAA;QACE,IAAMC,eAAe5G,aAAa6G,OAAO,CAAC,IAAI,CAACtG,UAAU;QACzD,IAAI,CAACA,UAAU,GAAGP,YAAY,CAAC,AAAC4G,CAAAA,eAAe,CAAA,IAAK5G,aAAakC,MAAM,CAAC;QACxE,sCAAsC;QACtC,IAAI,CAACe,OAAO,CAAC6D,OAAO;QACpB,oDAAoD;QACpD,IAAI,CAACzG,UAAU,GAAG;QAClB,IAAI,CAAC6E,MAAM;IACb;IAEA6B,OAAAA,eAQC,GARDA,SAAAA;QACE,IAAMH,eAAe5G,aAAa6G,OAAO,CAAC,IAAI,CAACtG,UAAU;QACzD,IAAI,CAACA,UAAU,GAAGP,YAAY,CAAC,AAAC4G,CAAAA,eAAe,IAAI5G,aAAakC,MAAM,AAAD,IAAKlC,aAAakC,MAAM,CAAC;QAC9F,sCAAsC;QACtC,IAAI,CAACe,OAAO,CAAC6D,OAAO;QACpB,oDAAoD;QACpD,IAAI,CAACzG,UAAU,GAAG;QAClB,IAAI,CAAC6E,MAAM;IACb;IAEA,cAAc;IACd8B,OAAAA,WAIC,GAJDA,SAAAA;QACE,IAAI,CAACvG,WAAW,GAAG;QACnB,IAAI,CAACD,UAAU,GAAG;QAClB,IAAI,CAAC0E,MAAM;IACb;IAEA+B,OAAAA,gBAKC,GALDA,SAAAA,iBAAiBnD,IAAY;QAC3B,IAAI,CAACtD,UAAU,GAAGsD;QAClB,sCAAsC;QACtC,IAAI,CAACb,OAAO,CAAC6D,OAAO;QACpB,IAAI,CAAC5B,MAAM;IACb;IAEAgC,OAAAA,YAMC,GANDA,SAAAA;QACE,IAAI,CAACzG,WAAW,GAAG;QACnB,IAAI,CAACD,UAAU,GAAG;QAClB,kBAAkB;QAClB,IAAI,CAACyC,OAAO,CAAC6D,OAAO;QACpB,IAAI,CAAC5B,MAAM;IACb;IAEAiC,OAAAA,aAKC,GALDA,SAAAA;QACE,IAAI,CAAC1G,WAAW,GAAG;QACnB,0DAA0D;QAC1D,IAAI,CAACwC,OAAO,CAAC6D,OAAO;QACpB,IAAI,CAAC5B,MAAM;IACb;IAEAkC,OAAAA,WAIC,GAJDA,SAAAA;QACE,IAAI,CAAC5G,UAAU,GAAG;QAClB,IAAI,CAACyC,OAAO,CAAC6D,OAAO;QACpB,IAAI,CAAC5B,MAAM;IACb;IAEA,4CAA4C;IAC5CmC,OAAAA,eAYC,GAZDA,SAAAA;QACE,qDAAqD;QACrD,IAAI,CAAC,IAAI,CAAChH,UAAU,EAAE;YACpB,IAAMiH,WAAW,IAAI,CAACZ,kBAAkB;YACxC,IAAIY,UAAU;gBACZ,IAAI,CAACjH,UAAU,GAAGiH,SAASzF,EAAE;YAC/B;QACF;QACA,IAAI,IAAI,CAACxB,UAAU,EAAE;YACnB,IAAI,CAACK,YAAY,GAAG;YACpB,IAAI,CAACwE,MAAM;QACb;IACF;IAEAqC,OAAAA,cAQC,GARDA,SAAAA,eAAeC,yBAAkC;QAC/C,IAAI,CAAC9G,YAAY,GAAG;QACpB,wCAAwC;QACxC,IAAI,CAACL,UAAU,GAAG;QAClB,IAAImH,2BAA2B;YAC7B,IAAI,CAACvE,OAAO,CAACwE,aAAa,CAACD;QAC7B;QACA,IAAI,CAACtC,MAAM;IACb;IAEA,kDAAkD;IAClDwC,OAAAA,iBAGC,GAHDA,SAAAA;QACE,IAAI,CAACpH,mBAAmB,GAAG,CAAC,IAAI,CAACA,mBAAmB;QACpD,IAAI,CAAC4E,MAAM;IACb;IAEAyC,OAAAA,iBAKC,GALDA,SAAAA;QACE,IAAI,CAAC,IAAI,CAACrH,mBAAmB,EAAE;YAC7B,IAAI,CAACA,mBAAmB,GAAG;YAC3B,IAAI,CAAC4E,MAAM;QACb;IACF;IAEA,kDAAkD;IAElD0C,OAAAA,UAKC,GALDA,SAAAA,WAAWC,YAAqB;QAC9B,IAAI,CAAC5E,OAAO,CAAC6E,IAAI;QACjB,IAAID,cAAc;YAChB,IAAI,CAAC5E,OAAO,CAAC8E,aAAa,CAACF;QAC7B;IACF;IAEAG,OAAAA,UAKC,GALDA,SAAAA,WAAWH,YAAqB;QAC9B,IAAI,CAAC5E,OAAO,CAACgF,EAAE;QACf,IAAIJ,cAAc;YAChB,IAAI,CAAC5E,OAAO,CAAC8E,aAAa,CAACF;QAC7B;IACF;IAEAK,OAAAA,cAEC,GAFDA,SAAAA,eAAeC,QAAgB,EAAEN,YAAqB;QACpD,IAAI,CAAC5E,OAAO,CAACmF,QAAQ,CAACD,UAAUN;IAClC;IAEAQ,OAAAA,YAEC,GAFDA,SAAAA,aAAaF,QAAgB,EAAEN,YAAqB;QAClD,IAAI,CAAC5E,OAAO,CAACqF,MAAM,CAACH,UAAUN;IAChC;IAEAU,OAAAA,WAKC,GALDA,SAAAA,YAAYV,YAAqB;QAC/B,IAAI,CAAC5E,OAAO,CAAC6D,OAAO;QACpB,IAAIe,cAAc;YAChB,IAAI,CAAC5E,OAAO,CAAC8E,aAAa,CAACF;QAC7B;IACF;IAEAW,OAAAA,UAKC,GALDA,SAAAA,WAAWX,YAAqB;QAC9B,IAAI,CAAC5E,OAAO,CAACwF,KAAK;QAClB,IAAIZ,cAAc;YAChB,IAAI,CAAC5E,OAAO,CAAC8E,aAAa,CAACF;QAC7B;IACF;IAEAa,OAAAA,iBAKC,GALDA,SAAAA,kBAAkBb,YAAoB;QACpC,IAAMc,UAAU,IAAI,CAAC1F,OAAO,CAACwE,aAAa,CAACI;QAC3C,IAAIc,SAAS;YACX,IAAI,CAACzD,MAAM;QACb;IACF;IAEA,wEAAwE;IAExE,OAAQ0D,cAKP,GALD,SAAQA;YAEM;QADZ,IAAI,CAAC,IAAI,CAACvI,UAAU,EAAE,OAAO0B;QAC7B,IAAM8G,OAAM,mBAAA,IAAI,CAAC1E,UAAU,CAAC,IAAI,CAAC9D,UAAU,eAA/B,uCAAA,iBAAkC+D,SAAS;QACvD,IAAI,CAACyE,KAAK,OAAO9G;QACjB,OAAO;YAAE8G,KAAAA;YAAKhH,IAAI,IAAI,CAACxB,UAAU;QAAC;IACpC;IAEAyI,OAAAA,UAWC,GAXDA,SAAAA,WAAWC,UAAkB;QAC3B,IAAMC,WAAW,IAAI,CAACJ,cAAc;QACpC,IAAI,CAACI,UAAU;QAEf,IAAMzC,YAAY,IAAI,CAACzD,mBAAmB,CAACkG,SAASnH,EAAE;QACtD,IAAMoH,YAAY7G,KAAKE,GAAG,CAAC,GAAGiE,YAAYwC;QAE1C,+BAA+B;QAC/B,IAAIC,SAASH,GAAG,CAAC3F,QAAQ,GAAG+F,WAAW;YACrCD,SAASH,GAAG,CAACf,IAAI;QACnB;IACF;IAEAoB,OAAAA,QAOC,GAPDA,SAAAA;QACE,IAAMF,WAAW,IAAI,CAACJ,cAAc;QACpC,IAAI,CAACI,UAAU;QAEf,IAAIA,SAASH,GAAG,CAAC3F,QAAQ,GAAG,GAAG;YAC7B8F,SAASH,GAAG,CAACZ,EAAE;QACjB;IACF;IAEAkB,OAAAA,cAWC,GAXDA,SAAAA,eAAehB,QAAgB;QAC7B,IAAMa,WAAW,IAAI,CAACJ,cAAc;QACpC,IAAI,CAACI,UAAU;QAEf,IAAMzC,YAAY,IAAI,CAACzD,mBAAmB,CAACkG,SAASnH,EAAE;QACtD,IAAMoH,YAAY7G,KAAKE,GAAG,CAAC,GAAGiE,YAAY4B;QAE1C,sBAAsB;QACtB,IAAMiB,cAAchH,KAAKiH,GAAG,CAACL,SAASH,GAAG,CAAC3F,QAAQ,GAAGiF,UAAUc;QAC/DD,SAASH,GAAG,CAACpC,WAAW,CAAC2C;QACzB,IAAI,CAAClE,MAAM;IACb;IAEAoE,OAAAA,YAOC,GAPDA,SAAAA,aAAanB,QAAgB;QAC3B,IAAMa,WAAW,IAAI,CAACJ,cAAc;QACpC,IAAI,CAACI,UAAU;QAEf,IAAMI,cAAchH,KAAKE,GAAG,CAAC,GAAG0G,SAASH,GAAG,CAAC3F,QAAQ,GAAGiF;QACxDa,SAASH,GAAG,CAACpC,WAAW,CAAC2C;QACzB,IAAI,CAAClE,MAAM;IACb;IAEAqE,OAAAA,WAIC,GAJDA,SAAAA;QACE,IAAMP,WAAW,IAAI,CAACJ,cAAc;QACpC,IAAI,CAACI,UAAU;QACfA,SAASH,GAAG,CAAC/B,OAAO;IACtB;IAEA0C,OAAAA,cAQC,GARDA,SAAAA,eAAeT,UAAkB;QAC/B,IAAMC,WAAW,IAAI,CAACJ,cAAc;QACpC,IAAI,CAACI,UAAU;QAEf,IAAMzC,YAAY,IAAI,CAACzD,mBAAmB,CAACkG,SAASnH,EAAE;QACtD,IAAMuH,cAAchH,KAAKE,GAAG,CAAC,GAAGiE,YAAYwC;QAC5CC,SAASH,GAAG,CAACpC,WAAW,CAAC2C;QACzB,IAAI,CAAClE,MAAM;IACb;IAEA,oBAAoB;IAEpBuE,OAAAA,YAoBC,GApBDA,SAAAA,aAAaC,wBAAiC,EAAElC,yBAAkC;QAChF,IAAMF,WAAW,IAAI,CAACZ,kBAAkB;QACxC,IAAI,CAACY,UAAU;QAEf,IAAI,IAAI,CAACjH,UAAU,KAAKiH,SAASzF,EAAE,EAAE;YACnC,4CAA4C;YAC5C,IAAI,CAACxB,UAAU,GAAG;YAClB,iDAAiD;YACjD,IAAImH,2BAA2B;gBAC7B,IAAI,CAACvE,OAAO,CAACwE,aAAa,CAACD;YAC7B;QACF,OAAO;YACL,6DAA6D;YAC7D,IAAI,CAACnH,UAAU,GAAGiH,SAASzF,EAAE;YAC7B,sDAAsD;YACtD,IAAI6H,0BAA0B;gBAC5B,IAAI,CAACzG,OAAO,CAAC8E,aAAa,CAAC2B;YAC7B;QACF;QACA,IAAI,CAACxE,MAAM;IACb;IAEAyE,OAAAA,QAQC,GARDA,SAAAA,SAASnC,yBAAkC;QACzC,+CAA+C;QAC/C,IAAI,CAACnH,UAAU,GAAG;QAClB,iDAAiD;QACjD,IAAImH,2BAA2B;YAC7B,IAAI,CAACvE,OAAO,CAACwE,aAAa,CAACD;QAC7B;QACA,IAAI,CAACtC,MAAM;IACb;IAEA,eAAe;IAEf0E,OAAAA,UAIC,GAJDA,SAAAA,WAAWC,QAAoB;QAC7B,IAAI,CAAC9I,UAAU,GAAG;QAClB,IAAI,CAACC,YAAY,GAAG6I;QACpB,IAAI,CAAC3E,MAAM;IACb;IAKA,gBAAgB;IAEhB4E,OAAAA,KAkBC,GAlBDA,SAAAA;YAEO,kCAAA,2BAAA;;YADL,2CAA2C;YAC3C,QAAK,YAAiB,IAAI,CAAC5J,SAAS,qBAA/B,SAAA,6BAAA,QAAA,yBAAA,iCAAiC;gBAAjC,IAAMgE,UAAN;oBACHA;iBAAAA,0BAAAA,QAAQ+B,cAAc,cAAtB/B,8CAAAA,wBAAwB6F,OAAO;YACjC;;YAFK;YAAA;;;qBAAA,6BAAA;oBAAA;;;oBAAA;0BAAA;;;;QAGL,IAAI,CAAC7J,SAAS,GAAG,EAAE;QACnB,IAAI,CAACC,YAAY,GAAG,EAAE;QACtB,IAAI,CAACY,UAAU,GAAG;QAClB,IAAI,CAACC,YAAY,GAAG;QACpB,IAAI,CAACZ,IAAI,GAAG;QACZ,IAAI,CAAC6C,OAAO,CAAC6G,KAAK;QAClB,IAAI,CAACzJ,UAAU,GAAG;QAClB,IAAI,CAACC,mBAAmB,GAAG;QAC3B,IAAI,CAACC,UAAU,GAAG;QAClB,IAAI,CAACC,UAAU,GAAG;QAClB,IAAI,CAACC,WAAW,GAAG;QACnB,IAAI,CAACC,YAAY,GAAG;QACpB,IAAI,CAAC4D,MAAM,GAAGvC;IAChB;IAEA,yBAAyB;IAEzBmD,OAAAA,MAKC,GALDA,SAAAA;QACE,IAAI,CAACjE,aAAa;QAClB,IAAI,CAACJ,SAAS,CAACmJ,OAAO,CAAC,SAACC;YACtBA;QACF;IACF;WAvfWlK;EA0fb,qEAAqE"}
|
|
@@ -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 }) {
|
|
@@ -26,6 +27,7 @@ function AppContent({ store }) {
|
|
|
26
27
|
const filterMode = useSyncExternalStore(store.subscribe, store.getFilterMode);
|
|
27
28
|
const searchTerm = useSyncExternalStore(store.subscribe, store.getSearchTerm);
|
|
28
29
|
const isSearching = useSyncExternalStore(store.subscribe, store.getIsSearching);
|
|
30
|
+
const isFullscreen = useSyncExternalStore(store.subscribe, store.getIsFullscreen);
|
|
29
31
|
// Subscribe to buffer version to trigger re-renders when terminal buffer content changes
|
|
30
32
|
const _bufferVersion = useSyncExternalStore(store.subscribe, store.getBufferVersion);
|
|
31
33
|
// Use filtered processes for display
|
|
@@ -88,8 +90,32 @@ function AppContent({ store }) {
|
|
|
88
90
|
visibleProcessCount,
|
|
89
91
|
store
|
|
90
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
|
|
91
95
|
// Keyboard handling (only active when raw mode is supported)
|
|
92
96
|
useInput((input, key)=>{
|
|
97
|
+
// Fullscreen mode input handling
|
|
98
|
+
if (isFullscreen) {
|
|
99
|
+
// Pre-calculate for viewport adjustment
|
|
100
|
+
const baseReserved = (header ? 2 : 0) + (showStatusBar ? 2 : 0);
|
|
101
|
+
const visibleWhenCollapsed = Math.max(1, terminalHeight - baseReserved - 2);
|
|
102
|
+
if (input === 'q' || key.escape || key.return) {
|
|
103
|
+
store.exitFullscreen(visibleWhenCollapsed);
|
|
104
|
+
} else if (key.meta && key.upArrow || input === 'g') {
|
|
105
|
+
store.scrollToTop();
|
|
106
|
+
} else if (key.meta && key.downArrow || input === 'G') {
|
|
107
|
+
store.scrollToBottom(fullscreenVisibleLines);
|
|
108
|
+
} else if (key.tab && key.shift) {
|
|
109
|
+
store.scrollPageUp(fullscreenVisibleLines);
|
|
110
|
+
} else if (key.tab && !key.shift) {
|
|
111
|
+
store.scrollPageDown(fullscreenVisibleLines);
|
|
112
|
+
} else if (key.downArrow || input === 'j') {
|
|
113
|
+
store.scrollDown(fullscreenVisibleLines);
|
|
114
|
+
} else if (key.upArrow || input === 'k') {
|
|
115
|
+
store.scrollUp();
|
|
116
|
+
}
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
93
119
|
// Search mode input handling
|
|
94
120
|
if (isSearching) {
|
|
95
121
|
if (key.escape) {
|
|
@@ -122,7 +148,11 @@ function AppContent({ store }) {
|
|
|
122
148
|
} else {
|
|
123
149
|
store.signalExit(()=>{});
|
|
124
150
|
}
|
|
151
|
+
// Enter - fullscreen view (direct from list or from expanded)
|
|
125
152
|
} else if (key.return) {
|
|
153
|
+
store.enterFullscreen();
|
|
154
|
+
// Space - toggle small expanded preview
|
|
155
|
+
} else if (input === ' ') {
|
|
126
156
|
store.toggleExpand(visibleWhenExpanded, visibleWhenCollapsed);
|
|
127
157
|
// Filter cycling - left/right arrows
|
|
128
158
|
} else if (key.rightArrow && !expandedId) {
|
|
@@ -195,6 +225,17 @@ function AppContent({ store }) {
|
|
|
195
225
|
// Force full re-render when layout structure changes
|
|
196
226
|
// Note: scrollOffset is NOT included - scrolling within expansion doesn't change structure
|
|
197
227
|
const layoutKey = `${listScrollOffset}-${expandedId}-${errorCount}-${errorFooterExpanded}-${filterMode}-${searchTerm}-${isSearching}`;
|
|
228
|
+
// Get expanded process info for fullscreen
|
|
229
|
+
const expandedProcess = expandedId ? store.getProcess(expandedId) : null;
|
|
230
|
+
// Render fullscreen overlay when active
|
|
231
|
+
if (isFullscreen && expandedProcess) {
|
|
232
|
+
return /*#__PURE__*/ _jsx(FullscreenOverlay, {
|
|
233
|
+
title: expandedProcess.group || expandedProcess.title,
|
|
234
|
+
lines: store.getProcessLines(expandedProcess.id),
|
|
235
|
+
scrollOffset: scrollOffset,
|
|
236
|
+
onExit: ()=>store.exitFullscreen()
|
|
237
|
+
});
|
|
238
|
+
}
|
|
198
239
|
return /*#__PURE__*/ _jsxs(Box, {
|
|
199
240
|
flexDirection: "column",
|
|
200
241
|
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 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 // 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 // Keyboard handling (only active when raw mode is supported)\n useInput(\n (input, key) => {\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 // 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 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","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","_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","input","key","escape","cancelSearch","return","confirmSearch","backspace","delete","updateSearchTerm","slice","ctrl","meta","toggleErrorFooter","baseReserved","visibleWhenExpanded","visibleWhenCollapsed","collapse","clearSearch","signalExit","toggleExpand","rightArrow","cycleFilterNext","leftArrow","cycleFilterPrev","startSearch","upArrow","scrollToTop","selectFirst","downArrow","scrollToBottom","selectLast","tab","shift","scrollPageUp","selectPageUp","scrollPageDown","selectPageDown","scrollDown","selectNext","scrollUp","selectPrev","isActive","visibleProcesses","showSelection","layoutKey","flexDirection","dimColor","color","bold","length","map","item","originalIndex","indexOf","isSelected","id","lines","getProcessLines","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 // Pre-calculate for viewport adjustment\n const baseReserved = (header ? 2 : 0) + (showStatusBar ? 2 : 0);\n const visibleWhenCollapsed = Math.max(1, terminalHeight - baseReserved - 2);\n\n if (input === 'q' || key.escape || key.return) {\n store.exitFullscreen(visibleWhenCollapsed);\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 // Enter - fullscreen view (direct from list or from expanded)\n } else if (key.return) {\n store.enterFullscreen();\n // Space - toggle small expanded preview\n } else if (input === ' ') {\n store.toggleExpand(visibleWhenExpanded, visibleWhenCollapsed);\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","baseReserved","visibleWhenCollapsed","escape","return","exitFullscreen","meta","upArrow","scrollToTop","downArrow","scrollToBottom","tab","shift","scrollPageUp","scrollPageDown","scrollDown","scrollUp","cancelSearch","confirmSearch","backspace","delete","updateSearchTerm","slice","ctrl","toggleErrorFooter","visibleWhenExpanded","collapse","clearSearch","signalExit","enterFullscreen","toggleExpand","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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"}
|
|
@@ -27,15 +27,18 @@ export default /*#__PURE__*/ memo(function ExpandedOutput({ lines, scrollOffset,
|
|
|
27
27
|
line.text
|
|
28
28
|
]
|
|
29
29
|
}, scrollOffset + i)),
|
|
30
|
-
hasMore
|
|
30
|
+
hasMore ? /*#__PURE__*/ _jsxs(Text, {
|
|
31
31
|
dimColor: true,
|
|
32
32
|
children: [
|
|
33
33
|
"│ [+",
|
|
34
34
|
remaining,
|
|
35
35
|
" more, Tab/⇧Tab page, ",
|
|
36
36
|
isMac ? '⌥↑/↓' : 'g/G',
|
|
37
|
-
" top/bottom]"
|
|
37
|
+
" top/bottom, ↵ fullscreen]"
|
|
38
38
|
]
|
|
39
|
+
}) : /*#__PURE__*/ _jsx(Text, {
|
|
40
|
+
dimColor: true,
|
|
41
|
+
children: "│ [↵ fullscreen]"
|
|
39
42
|
})
|
|
40
43
|
]
|
|
41
44
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/node/spawn-term/src/components/ExpandedOutput.tsx"],"sourcesContent":["import { Box, Text } from 'ink';\nimport { memo } from 'react';\nimport { EXPANDED_MAX_VISIBLE_LINES } from '../constants.ts';\nimport type { Line } from '../types.ts';\n\nconst isMac = process.platform === 'darwin';\n\ntype Props = {\n lines: Line[];\n scrollOffset: number;\n maxVisible?: number;\n};\n\nexport default memo(function ExpandedOutput({ lines, scrollOffset, maxVisible = EXPANDED_MAX_VISIBLE_LINES }: Props) {\n const visibleLines = lines.slice(scrollOffset, scrollOffset + maxVisible);\n const hasMore = lines.length > scrollOffset + maxVisible;\n const remaining = lines.length - scrollOffset - maxVisible;\n\n if (lines.length === 0) {\n return (\n <Box paddingLeft={2}>\n <Text dimColor>│ (no output)</Text>\n </Box>\n );\n }\n\n return (\n <Box flexDirection=\"column\" paddingLeft={2}>\n {visibleLines.map((line, i) => (\n // biome-ignore lint/suspicious/noArrayIndexKey: Lines have no unique ID, index is stable for this scrolling view\n <Text key={scrollOffset + i}>│ {line.text}</Text>\n ))}\n {hasMore
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/node/spawn-term/src/components/ExpandedOutput.tsx"],"sourcesContent":["import { Box, Text } from 'ink';\nimport { memo } from 'react';\nimport { EXPANDED_MAX_VISIBLE_LINES } from '../constants.ts';\nimport type { Line } from '../types.ts';\n\nconst isMac = process.platform === 'darwin';\n\ntype Props = {\n lines: Line[];\n scrollOffset: number;\n maxVisible?: number;\n};\n\nexport default memo(function ExpandedOutput({ lines, scrollOffset, maxVisible = EXPANDED_MAX_VISIBLE_LINES }: Props) {\n const visibleLines = lines.slice(scrollOffset, scrollOffset + maxVisible);\n const hasMore = lines.length > scrollOffset + maxVisible;\n const remaining = lines.length - scrollOffset - maxVisible;\n\n if (lines.length === 0) {\n return (\n <Box paddingLeft={2}>\n <Text dimColor>│ (no output)</Text>\n </Box>\n );\n }\n\n return (\n <Box flexDirection=\"column\" paddingLeft={2}>\n {visibleLines.map((line, i) => (\n // biome-ignore lint/suspicious/noArrayIndexKey: Lines have no unique ID, index is stable for this scrolling view\n <Text key={scrollOffset + i}>│ {line.text}</Text>\n ))}\n {hasMore ? (\n <Text dimColor>\n │ [+{remaining} more, Tab/⇧Tab page, {isMac ? '⌥↑/↓' : 'g/G'} top/bottom, ↵ fullscreen]\n </Text>\n ) : (\n <Text dimColor>│ [↵ fullscreen]</Text>\n )}\n </Box>\n );\n});\n"],"names":["Box","Text","memo","EXPANDED_MAX_VISIBLE_LINES","isMac","process","platform","ExpandedOutput","lines","scrollOffset","maxVisible","visibleLines","slice","hasMore","length","remaining","paddingLeft","dimColor","flexDirection","map","line","i","text"],"mappings":";AAAA,SAASA,GAAG,EAAEC,IAAI,QAAQ,MAAM;AAChC,SAASC,IAAI,QAAQ,QAAQ;AAC7B,SAASC,0BAA0B,QAAQ,kBAAkB;AAG7D,MAAMC,QAAQC,QAAQC,QAAQ,KAAK;AAQnC,6BAAeJ,KAAK,SAASK,eAAe,EAAEC,KAAK,EAAEC,YAAY,EAAEC,aAAaP,0BAA0B,EAAS;IACjH,MAAMQ,eAAeH,MAAMI,KAAK,CAACH,cAAcA,eAAeC;IAC9D,MAAMG,UAAUL,MAAMM,MAAM,GAAGL,eAAeC;IAC9C,MAAMK,YAAYP,MAAMM,MAAM,GAAGL,eAAeC;IAEhD,IAAIF,MAAMM,MAAM,KAAK,GAAG;QACtB,qBACE,KAACd;YAAIgB,aAAa;sBAChB,cAAA,KAACf;gBAAKgB,QAAQ;0BAAC;;;IAGrB;IAEA,qBACE,MAACjB;QAAIkB,eAAc;QAASF,aAAa;;YACtCL,aAAaQ,GAAG,CAAC,CAACC,MAAMC,IACvB,iHAAiH;8BACjH,MAACpB;;wBAA4B;wBAAGmB,KAAKE,IAAI;;mBAA9Bb,eAAeY;YAE3BR,wBACC,MAACZ;gBAAKgB,QAAQ;;oBAAC;oBACRF;oBAAU;oBAAuBX,QAAQ,SAAS;oBAAM;;+BAG/D,KAACH;gBAAKgB,QAAQ;0BAAC;;;;AAIvB,GAAG"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Box, Text, useStdout } from 'ink';
|
|
3
|
+
import { memo, useEffect } from 'react';
|
|
4
|
+
const isMac = process.platform === 'darwin';
|
|
5
|
+
// ANSI escape codes for alternate screen buffer
|
|
6
|
+
const ENTER_ALT_SCREEN = '\x1b[?1049h';
|
|
7
|
+
const EXIT_ALT_SCREEN = '\x1b[?1049l';
|
|
8
|
+
const CLEAR_SCREEN = '\x1b[2J';
|
|
9
|
+
const CURSOR_HOME = '\x1b[H';
|
|
10
|
+
export default /*#__PURE__*/ memo(function FullscreenOverlay({ title, lines, scrollOffset }) {
|
|
11
|
+
const { stdout } = useStdout();
|
|
12
|
+
const terminalHeight = (stdout === null || stdout === void 0 ? void 0 : stdout.rows) || 24;
|
|
13
|
+
// Reserve lines for header (title + divider) and footer (scroll hint)
|
|
14
|
+
const headerLines = 2;
|
|
15
|
+
const footerLines = 1;
|
|
16
|
+
const maxVisible = Math.max(1, terminalHeight - headerLines - footerLines);
|
|
17
|
+
// Enter alternate screen on mount, exit on unmount
|
|
18
|
+
useEffect(()=>{
|
|
19
|
+
if (stdout) {
|
|
20
|
+
stdout.write(ENTER_ALT_SCREEN + CLEAR_SCREEN + CURSOR_HOME);
|
|
21
|
+
}
|
|
22
|
+
return ()=>{
|
|
23
|
+
if (stdout) {
|
|
24
|
+
stdout.write(EXIT_ALT_SCREEN);
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
}, [
|
|
28
|
+
stdout
|
|
29
|
+
]);
|
|
30
|
+
const visibleLines = lines.slice(scrollOffset, scrollOffset + maxVisible);
|
|
31
|
+
const totalLines = lines.length;
|
|
32
|
+
const currentLine = scrollOffset + 1;
|
|
33
|
+
const endLine = Math.min(scrollOffset + maxVisible, totalLines);
|
|
34
|
+
return /*#__PURE__*/ _jsxs(Box, {
|
|
35
|
+
flexDirection: "column",
|
|
36
|
+
height: terminalHeight,
|
|
37
|
+
children: [
|
|
38
|
+
/*#__PURE__*/ _jsx(Text, {
|
|
39
|
+
bold: true,
|
|
40
|
+
color: "cyan",
|
|
41
|
+
children: title
|
|
42
|
+
}),
|
|
43
|
+
/*#__PURE__*/ _jsx(Text, {
|
|
44
|
+
dimColor: true,
|
|
45
|
+
children: '─'.repeat(Math.min(80, (stdout === null || stdout === void 0 ? void 0 : stdout.columns) || 80))
|
|
46
|
+
}),
|
|
47
|
+
/*#__PURE__*/ _jsx(Box, {
|
|
48
|
+
flexDirection: "column",
|
|
49
|
+
flexGrow: 1,
|
|
50
|
+
children: lines.length === 0 ? /*#__PURE__*/ _jsx(Text, {
|
|
51
|
+
dimColor: true,
|
|
52
|
+
children: "(no output)"
|
|
53
|
+
}) : visibleLines.map((line, i)=>// biome-ignore lint/suspicious/noArrayIndexKey: Lines have no unique ID, index is stable for this scrolling view
|
|
54
|
+
/*#__PURE__*/ _jsx(Text, {
|
|
55
|
+
children: line.text
|
|
56
|
+
}, scrollOffset + i))
|
|
57
|
+
}),
|
|
58
|
+
/*#__PURE__*/ _jsxs(Text, {
|
|
59
|
+
dimColor: true,
|
|
60
|
+
children: [
|
|
61
|
+
"Lines ",
|
|
62
|
+
currentLine,
|
|
63
|
+
"-",
|
|
64
|
+
endLine,
|
|
65
|
+
" of ",
|
|
66
|
+
totalLines,
|
|
67
|
+
" | j/k scroll | Tab/⇧Tab page | ",
|
|
68
|
+
isMac ? '⌥↑/↓' : 'g/G',
|
|
69
|
+
" top/bottom | ↵/q exit"
|
|
70
|
+
]
|
|
71
|
+
})
|
|
72
|
+
]
|
|
73
|
+
});
|
|
74
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/node/spawn-term/src/components/FullscreenOverlay.tsx"],"sourcesContent":["import { Box, Text, useStdout } from 'ink';\nimport { memo, useEffect } from 'react';\nimport type { Line } from '../types.ts';\n\nconst isMac = process.platform === 'darwin';\n\n// ANSI escape codes for alternate screen buffer\nconst ENTER_ALT_SCREEN = '\\x1b[?1049h';\nconst EXIT_ALT_SCREEN = '\\x1b[?1049l';\nconst CLEAR_SCREEN = '\\x1b[2J';\nconst CURSOR_HOME = '\\x1b[H';\n\ntype Props = {\n title: string;\n lines: Line[];\n scrollOffset: number;\n onExit: () => void;\n};\n\nexport default memo(function FullscreenOverlay({ title, lines, scrollOffset }: Props) {\n const { stdout } = useStdout();\n const terminalHeight = stdout?.rows || 24;\n\n // Reserve lines for header (title + divider) and footer (scroll hint)\n const headerLines = 2;\n const footerLines = 1;\n const maxVisible = Math.max(1, terminalHeight - headerLines - footerLines);\n\n // Enter alternate screen on mount, exit on unmount\n useEffect(() => {\n if (stdout) {\n stdout.write(ENTER_ALT_SCREEN + CLEAR_SCREEN + CURSOR_HOME);\n }\n return () => {\n if (stdout) {\n stdout.write(EXIT_ALT_SCREEN);\n }\n };\n }, [stdout]);\n\n const visibleLines = lines.slice(scrollOffset, scrollOffset + maxVisible);\n const totalLines = lines.length;\n const currentLine = scrollOffset + 1;\n const endLine = Math.min(scrollOffset + maxVisible, totalLines);\n\n return (\n <Box flexDirection=\"column\" height={terminalHeight}>\n {/* Header */}\n <Text bold color=\"cyan\">\n {title}\n </Text>\n <Text dimColor>{'─'.repeat(Math.min(80, stdout?.columns || 80))}</Text>\n\n {/* Content */}\n <Box flexDirection=\"column\" flexGrow={1}>\n {lines.length === 0 ? (\n <Text dimColor>(no output)</Text>\n ) : (\n visibleLines.map((line, i) => (\n // biome-ignore lint/suspicious/noArrayIndexKey: Lines have no unique ID, index is stable for this scrolling view\n <Text key={scrollOffset + i}>{line.text}</Text>\n ))\n )}\n </Box>\n\n {/* Footer */}\n <Text dimColor>\n Lines {currentLine}-{endLine} of {totalLines} | j/k scroll | Tab/⇧Tab page | {isMac ? '⌥↑/↓' : 'g/G'} top/bottom | ↵/q exit\n </Text>\n </Box>\n );\n});\n"],"names":["Box","Text","useStdout","memo","useEffect","isMac","process","platform","ENTER_ALT_SCREEN","EXIT_ALT_SCREEN","CLEAR_SCREEN","CURSOR_HOME","FullscreenOverlay","title","lines","scrollOffset","stdout","terminalHeight","rows","headerLines","footerLines","maxVisible","Math","max","write","visibleLines","slice","totalLines","length","currentLine","endLine","min","flexDirection","height","bold","color","dimColor","repeat","columns","flexGrow","map","line","i","text"],"mappings":";AAAA,SAASA,GAAG,EAAEC,IAAI,EAAEC,SAAS,QAAQ,MAAM;AAC3C,SAASC,IAAI,EAAEC,SAAS,QAAQ,QAAQ;AAGxC,MAAMC,QAAQC,QAAQC,QAAQ,KAAK;AAEnC,gDAAgD;AAChD,MAAMC,mBAAmB;AACzB,MAAMC,kBAAkB;AACxB,MAAMC,eAAe;AACrB,MAAMC,cAAc;AASpB,6BAAeR,KAAK,SAASS,kBAAkB,EAAEC,KAAK,EAAEC,KAAK,EAAEC,YAAY,EAAS;IAClF,MAAM,EAAEC,MAAM,EAAE,GAAGd;IACnB,MAAMe,iBAAiBD,CAAAA,mBAAAA,6BAAAA,OAAQE,IAAI,KAAI;IAEvC,sEAAsE;IACtE,MAAMC,cAAc;IACpB,MAAMC,cAAc;IACpB,MAAMC,aAAaC,KAAKC,GAAG,CAAC,GAAGN,iBAAiBE,cAAcC;IAE9D,mDAAmD;IACnDhB,UAAU;QACR,IAAIY,QAAQ;YACVA,OAAOQ,KAAK,CAAChB,mBAAmBE,eAAeC;QACjD;QACA,OAAO;YACL,IAAIK,QAAQ;gBACVA,OAAOQ,KAAK,CAACf;YACf;QACF;IACF,GAAG;QAACO;KAAO;IAEX,MAAMS,eAAeX,MAAMY,KAAK,CAACX,cAAcA,eAAeM;IAC9D,MAAMM,aAAab,MAAMc,MAAM;IAC/B,MAAMC,cAAcd,eAAe;IACnC,MAAMe,UAAUR,KAAKS,GAAG,CAAChB,eAAeM,YAAYM;IAEpD,qBACE,MAAC3B;QAAIgC,eAAc;QAASC,QAAQhB;;0BAElC,KAAChB;gBAAKiC,IAAI;gBAACC,OAAM;0BACdtB;;0BAEH,KAACZ;gBAAKmC,QAAQ;0BAAE,IAAIC,MAAM,CAACf,KAAKS,GAAG,CAAC,IAAIf,CAAAA,mBAAAA,6BAAAA,OAAQsB,OAAO,KAAI;;0BAG3D,KAACtC;gBAAIgC,eAAc;gBAASO,UAAU;0BACnCzB,MAAMc,MAAM,KAAK,kBAChB,KAAC3B;oBAAKmC,QAAQ;8BAAC;qBAEfX,aAAae,GAAG,CAAC,CAACC,MAAMC,IACtB,iHAAiH;kCACjH,KAACzC;kCAA6BwC,KAAKE,IAAI;uBAA5B5B,eAAe2B;;0BAMhC,MAACzC;gBAAKmC,QAAQ;;oBAAC;oBACNP;oBAAY;oBAAEC;oBAAQ;oBAAKH;oBAAW;oBAAiCtB,QAAQ,SAAS;oBAAM;;;;;AAI7G,GAAG"}
|
|
@@ -12,6 +12,7 @@ export declare class ProcessStore {
|
|
|
12
12
|
private filterMode;
|
|
13
13
|
private searchTerm;
|
|
14
14
|
private isSearching;
|
|
15
|
+
private isFullscreen;
|
|
15
16
|
private header;
|
|
16
17
|
private showStatusBar;
|
|
17
18
|
private isInteractive;
|
|
@@ -49,6 +50,7 @@ export declare class ProcessStore {
|
|
|
49
50
|
getFilterMode: () => FilterMode;
|
|
50
51
|
getSearchTerm: () => string;
|
|
51
52
|
getIsSearching: () => boolean;
|
|
53
|
+
getIsFullscreen: () => boolean;
|
|
52
54
|
getFilteredProcesses: () => ChildProcess[];
|
|
53
55
|
getScrollOffset: () => number;
|
|
54
56
|
getHeader: () => string | undefined;
|
|
@@ -64,6 +66,8 @@ export declare class ProcessStore {
|
|
|
64
66
|
cancelSearch(): void;
|
|
65
67
|
confirmSearch(): void;
|
|
66
68
|
clearSearch(): void;
|
|
69
|
+
enterFullscreen(): void;
|
|
70
|
+
exitFullscreen(visibleCountWhenCollapsed?: number): void;
|
|
67
71
|
toggleErrorFooter(): void;
|
|
68
72
|
expandErrorFooter(): void;
|
|
69
73
|
selectNext(visibleCount?: number): void;
|
|
@@ -145,6 +145,29 @@ export class ProcessStore {
|
|
|
145
145
|
this.listNav.toStart();
|
|
146
146
|
this.notify();
|
|
147
147
|
}
|
|
148
|
+
// Fullscreen mode (alternate screen buffer)
|
|
149
|
+
enterFullscreen() {
|
|
150
|
+
// If not expanded, expand the selected process first
|
|
151
|
+
if (!this.expandedId) {
|
|
152
|
+
const selected = this.getSelectedProcess();
|
|
153
|
+
if (selected) {
|
|
154
|
+
this.expandedId = selected.id;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
if (this.expandedId) {
|
|
158
|
+
this.isFullscreen = true;
|
|
159
|
+
this.notify();
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
exitFullscreen(visibleCountWhenCollapsed) {
|
|
163
|
+
this.isFullscreen = false;
|
|
164
|
+
// Also collapse when exiting fullscreen
|
|
165
|
+
this.expandedId = null;
|
|
166
|
+
if (visibleCountWhenCollapsed) {
|
|
167
|
+
this.listNav.clampViewport(visibleCountWhenCollapsed);
|
|
168
|
+
}
|
|
169
|
+
this.notify();
|
|
170
|
+
}
|
|
148
171
|
// Error footer methods (for non-interactive mode)
|
|
149
172
|
toggleErrorFooter() {
|
|
150
173
|
this.errorFooterExpanded = !this.errorFooterExpanded;
|
|
@@ -305,6 +328,7 @@ export class ProcessStore {
|
|
|
305
328
|
this.filterMode = 'all';
|
|
306
329
|
this.searchTerm = '';
|
|
307
330
|
this.isSearching = false;
|
|
331
|
+
this.isFullscreen = false;
|
|
308
332
|
this.header = undefined;
|
|
309
333
|
}
|
|
310
334
|
// === INFRASTRUCTURE ===
|
|
@@ -325,6 +349,7 @@ export class ProcessStore {
|
|
|
325
349
|
this.filterMode = 'all';
|
|
326
350
|
this.searchTerm = '';
|
|
327
351
|
this.isSearching = false;
|
|
352
|
+
this.isFullscreen = false;
|
|
328
353
|
this.showStatusBar = false;
|
|
329
354
|
this.isInteractive = false;
|
|
330
355
|
// === INFRASTRUCTURE ===
|
|
@@ -370,6 +395,7 @@ export class ProcessStore {
|
|
|
370
395
|
this.getFilterMode = ()=>this.filterMode;
|
|
371
396
|
this.getSearchTerm = ()=>this.searchTerm;
|
|
372
397
|
this.getIsSearching = ()=>this.isSearching;
|
|
398
|
+
this.getIsFullscreen = ()=>this.isFullscreen;
|
|
373
399
|
// Get processes filtered by current filter mode and search term
|
|
374
400
|
this.getFilteredProcesses = ()=>{
|
|
375
401
|
let filtered = this.processes;
|
|
@@ -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';\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\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\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 // 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.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":["arrayFind","DEFAULT_COLUMN_WIDTH","LineType","createNavigator","FILTER_CYCLE","ProcessStore","getErrorLines","getFailedProcesses","map","p","processName","group","title","lines","getProcessLines","id","addProcess","process","processWithNav","scrollNav","getLength","getProcessLineCount","wrap","onMove","notify","processes","updateProcess","update","oldProcess","wasRunning","state","isNowComplete","completedIds","includes","isInteractive","isAllComplete","getErrorCount","errorFooterExpanded","appendLines","newLines","concat","getProcess","terminalBuffer","getLines","text","type","stdout","lineCount","length","setMode","mode","listNav","setPosition","getSelectedProcess","getFilteredProcesses","position","cycleFilterNext","currentIndex","indexOf","filterMode","toStart","expandedId","cycleFilterPrev","startSearch","isSearching","searchTerm","updateSearchTerm","term","cancelSearch","confirmSearch","clearSearch","toggleErrorFooter","expandErrorFooter","selectNext","visibleCount","down","ensureVisible","selectPrev","up","selectPageDown","pageSize","pageDown","selectPageUp","pageUp","selectFirst","selectLast","toEnd","clampListViewport","changed","clampViewport","getExpandedNav","undefined","nav","scrollDown","maxVisible","expanded","maxOffset","Math","max","scrollUp","scrollPageDown","newPosition","min","scrollPageUp","scrollToTop","scrollToBottom","toggleExpand","visibleCountWhenExpanded","visibleCountWhenCollapsed","selected","collapse","signalExit","callback","shouldExit","exitCallback","reset","dispose","header","bufferVersion","listeners","forEach","l","options","showStatusBar","Set","subscribe","listener","add","delete","getSnapshot","getRunningProcesses","filter","getCompletedProcesses","getRunningCount","getMaxGroupLength","getDoneCount","getErrorLineCount","reduce","total","getMode","getSelectedIndex","getExpandedId","getListScrollOffset","viewportOffset","getErrorFooterExpanded","getBufferVersion","getFilterMode","getSearchTerm","getIsSearching","filtered","toLowerCase","getScrollOffset","getHeader","getShowStatusBar","getIsInteractive","every","getShouldExit","getExitCallback","interactive"],"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 not expanded, expand the selected process first\n if (!this.expandedId) {\n const selected = this.getSelectedProcess();\n if (selected) {\n this.expandedId = selected.id;\n }\n }\n if (this.expandedId) {\n this.isFullscreen = true;\n this.notify();\n }\n }\n\n exitFullscreen(visibleCountWhenCollapsed?: number): void {\n this.isFullscreen = false;\n // Also collapse when exiting fullscreen\n this.expandedId = null;\n if (visibleCountWhenCollapsed) {\n this.listNav.clampViewport(visibleCountWhenCollapsed);\n }\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":["arrayFind","DEFAULT_COLUMN_WIDTH","LineType","createNavigator","FILTER_CYCLE","ProcessStore","getErrorLines","getFailedProcesses","map","p","processName","group","title","lines","getProcessLines","id","addProcess","process","processWithNav","scrollNav","getLength","getProcessLineCount","wrap","onMove","notify","processes","updateProcess","update","oldProcess","wasRunning","state","isNowComplete","completedIds","includes","isInteractive","isAllComplete","getErrorCount","errorFooterExpanded","appendLines","newLines","concat","getProcess","terminalBuffer","getLines","text","type","stdout","lineCount","length","setMode","mode","listNav","setPosition","getSelectedProcess","getFilteredProcesses","position","cycleFilterNext","currentIndex","indexOf","filterMode","toStart","expandedId","cycleFilterPrev","startSearch","isSearching","searchTerm","updateSearchTerm","term","cancelSearch","confirmSearch","clearSearch","enterFullscreen","selected","isFullscreen","exitFullscreen","visibleCountWhenCollapsed","clampViewport","toggleErrorFooter","expandErrorFooter","selectNext","visibleCount","down","ensureVisible","selectPrev","up","selectPageDown","pageSize","pageDown","selectPageUp","pageUp","selectFirst","selectLast","toEnd","clampListViewport","changed","getExpandedNav","undefined","nav","scrollDown","maxVisible","expanded","maxOffset","Math","max","scrollUp","scrollPageDown","newPosition","min","scrollPageUp","scrollToTop","scrollToBottom","toggleExpand","visibleCountWhenExpanded","collapse","signalExit","callback","shouldExit","exitCallback","reset","dispose","header","bufferVersion","listeners","forEach","l","options","showStatusBar","Set","subscribe","listener","add","delete","getSnapshot","getRunningProcesses","filter","getCompletedProcesses","getRunningCount","getMaxGroupLength","getDoneCount","getErrorLineCount","reduce","total","getMode","getSelectedIndex","getExpandedId","getListScrollOffset","viewportOffset","getErrorFooterExpanded","getBufferVersion","getFilterMode","getSearchTerm","getIsSearching","getIsFullscreen","filtered","toLowerCase","getScrollOffset","getHeader","getShowStatusBar","getIsInteractive","every","getShouldExit","getExitCallback","interactive"],"mappings":"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"}
|