spawn-term 3.0.5 → 3.0.7

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.
@@ -39,19 +39,23 @@ function AppContent(param) {
39
39
  var scrollOffset = (0, _react.useSyncExternalStore)(store.subscribe, store.getScrollOffset);
40
40
  var listScrollOffset = (0, _react.useSyncExternalStore)(store.subscribe, store.getListScrollOffset);
41
41
  var errorFooterExpanded = (0, _react.useSyncExternalStore)(store.subscribe, store.getErrorFooterExpanded);
42
+ // Subscribe to buffer version to trigger re-renders when terminal buffer content changes
43
+ var _bufferVersion = (0, _react.useSyncExternalStore)(store.subscribe, store.getBufferVersion);
42
44
  // Subscribed state that triggers re-renders
43
45
  var header = (0, _react.useSyncExternalStore)(store.subscribe, store.getHeader);
44
46
  var showStatusBar = (0, _react.useSyncExternalStore)(store.subscribe, store.getShowStatusBar);
45
47
  var isInteractive = (0, _react.useSyncExternalStore)(store.subscribe, store.getIsInteractive);
46
- // Calculate visible process count (reserve lines for header, divider, status bar)
47
- var reservedLines = (header ? 2 : 0) + (showStatusBar ? 2 : 0);
48
+ // Calculate visible process count (reserve lines for header, divider, status bar, expanded output)
49
+ // When a process is expanded, reserve space for the expanded output to prevent terminal scrolling
50
+ var expandedHeight = expandedId ? _constantsts.EXPANDED_MAX_VISIBLE_LINES + 1 : 0; // +1 for scroll hint
51
+ var reservedLines = (header ? 2 : 0) + (showStatusBar ? 2 : 0) + expandedHeight;
48
52
  var visibleProcessCount = Math.max(1, terminalHeight - reservedLines);
49
53
  // Derived state (computed from processes which is already subscribed)
50
54
  var runningCount = store.getRunningCount();
51
55
  var doneCount = store.getDoneCount();
52
56
  var errorCount = store.getErrorCount();
53
57
  var errorLineCount = store.getErrorLineCount();
54
- var isAllComplete = store.isAllComplete();
58
+ var _isAllComplete = store.isAllComplete();
55
59
  var errorLines = store.getErrorLines();
56
60
  // Handle exit signal
57
61
  (0, _react.useEffect)(function() {
@@ -62,13 +66,13 @@ function AppContent(param) {
62
66
  shouldExit,
63
67
  exit
64
68
  ]);
65
- // Auto-enter interactive mode when all complete and interactive flag is set
69
+ // Auto-enter interactive mode immediately when interactive flag is set
70
+ // This allows selecting and viewing logs of running processes
66
71
  (0, _react.useEffect)(function() {
67
- if (isAllComplete && isInteractive && mode === 'normal') {
72
+ if (isInteractive && mode === 'normal') {
68
73
  store.setMode('interactive');
69
74
  }
70
75
  }, [
71
- isAllComplete,
72
76
  isInteractive,
73
77
  mode,
74
78
  store
@@ -132,8 +136,13 @@ function AppContent(param) {
132
136
  ]);
133
137
  // Normal/Interactive view - render in original registration order
134
138
  var showSelection = mode === 'interactive';
139
+ // Force full re-render when layout HEIGHT changes (not content)
140
+ // Combined with incrementalRendering: false in session.tsx, this ensures clean redraws
141
+ // Note: scrollOffset is NOT included - scrolling within expansion doesn't change height
142
+ var layoutKey = "".concat(listScrollOffset, "-").concat(expandedId, "-").concat(errorCount, "-").concat(errorFooterExpanded);
135
143
  return /*#__PURE__*/ (0, _jsxruntime.jsxs)(_ink.Box, {
136
144
  flexDirection: "column",
145
+ height: terminalHeight,
137
146
  children: [
138
147
  header && /*#__PURE__*/ (0, _jsxruntime.jsxs)(_jsxruntime.Fragment, {
139
148
  children: [
@@ -155,13 +164,13 @@ function AppContent(param) {
155
164
  isSelected: showSelection && originalIndex === selectedIndex
156
165
  }),
157
166
  expandedId === item.id && /*#__PURE__*/ (0, _jsxruntime.jsx)(_ExpandedOutputts.default, {
158
- lines: item.lines,
167
+ lines: store.getProcessLines(item.id),
159
168
  scrollOffset: scrollOffset
160
169
  })
161
170
  ]
162
171
  }, item.id);
163
172
  })
164
- }, "processes-".concat(listScrollOffset)),
173
+ }),
165
174
  showStatusBar && processes.length > 0 && /*#__PURE__*/ (0, _jsxruntime.jsxs)(_jsxruntime.Fragment, {
166
175
  children: [
167
176
  /*#__PURE__*/ (0, _jsxruntime.jsx)(_Dividerts.default, {}),
@@ -178,7 +187,7 @@ function AppContent(param) {
178
187
  isExpanded: errorFooterExpanded
179
188
  })
180
189
  ]
181
- });
190
+ }, layoutKey);
182
191
  }
183
192
  function App(param) {
184
193
  var store = param.store;
@@ -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\ninterface AppProps {\n store: ProcessStore;\n}\n\nfunction AppContent({ store }: AppProps): React.JSX.Element {\n const { exit } = useApp();\n const { isRawModeSupported } = useStdin();\n const { stdout } = useStdout();\n const terminalHeight = stdout?.rows || 24;\n\n // Subscribe to store state\n const processes = useSyncExternalStore(store.subscribe, store.getSnapshot);\n const shouldExit = useSyncExternalStore(store.subscribe, store.getShouldExit);\n const mode = useSyncExternalStore(store.subscribe, store.getMode);\n const selectedIndex = useSyncExternalStore(store.subscribe, store.getSelectedIndex);\n const expandedId = useSyncExternalStore(store.subscribe, store.getExpandedId);\n const scrollOffset = useSyncExternalStore(store.subscribe, store.getScrollOffset);\n const listScrollOffset = useSyncExternalStore(store.subscribe, store.getListScrollOffset);\n const errorFooterExpanded = useSyncExternalStore(store.subscribe, store.getErrorFooterExpanded);\n\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)\n const reservedLines = (header ? 2 : 0) + (showStatusBar ? 2 : 0);\n const visibleProcessCount = Math.max(1, terminalHeight - reservedLines);\n\n // Derived state (computed from processes which is already subscribed)\n const runningCount = store.getRunningCount();\n const doneCount = store.getDoneCount();\n const errorCount = store.getErrorCount();\n const errorLineCount = store.getErrorLineCount();\n const isAllComplete = store.isAllComplete();\n const errorLines = store.getErrorLines();\n\n // Handle exit signal\n useEffect(() => {\n if (shouldExit) {\n exit();\n }\n }, [shouldExit, exit]);\n\n // Auto-enter interactive mode when all complete and interactive flag is set\n useEffect(() => {\n if (isAllComplete && isInteractive && mode === 'normal') {\n store.setMode('interactive');\n }\n }, [isAllComplete, isInteractive, mode, store]);\n\n // Keyboard handling (only active when raw mode is supported)\n useInput(\n (input, key) => {\n if (mode === 'normal') {\n // In non-interactive mode, 'e' toggles error footer\n if (input === 'e' && errorCount > 0) {\n store.toggleErrorFooter();\n }\n } else if (mode === 'interactive') {\n if (input === 'q' || key.escape) {\n if (expandedId) {\n store.collapse();\n } else {\n store.signalExit(() => {});\n }\n } else if (key.return) {\n store.toggleExpand();\n } else if (key.downArrow) {\n if (expandedId) {\n store.scrollDown(EXPANDED_MAX_VISIBLE_LINES);\n } else {\n store.selectNext(visibleProcessCount);\n }\n } else if (key.upArrow) {\n if (expandedId) {\n store.scrollUp();\n } else {\n store.selectPrev(visibleProcessCount);\n }\n } else if (input === 'j') {\n if (expandedId) {\n store.scrollDown(EXPANDED_MAX_VISIBLE_LINES);\n } else {\n store.selectNext(visibleProcessCount);\n }\n } else if (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 return (\n <Box flexDirection=\"column\">\n {/* Header */}\n {header && (\n <>\n <Text>{header}</Text>\n <Divider />\n </>\n )}\n\n {/* Visible processes - key forces clean re-render on scroll */}\n <Box key={`processes-${listScrollOffset}`} 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={item.lines} scrollOffset={scrollOffset} />}\n </Box>\n );\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","AppContent","store","exit","useApp","isRawModeSupported","useStdin","stdout","useStdout","terminalHeight","rows","processes","useSyncExternalStore","subscribe","getSnapshot","shouldExit","getShouldExit","mode","getMode","selectedIndex","getSelectedIndex","expandedId","getExpandedId","scrollOffset","getScrollOffset","listScrollOffset","getListScrollOffset","errorFooterExpanded","getErrorFooterExpanded","header","getHeader","showStatusBar","getShowStatusBar","isInteractive","getIsInteractive","reservedLines","visibleProcessCount","Math","max","runningCount","getRunningCount","doneCount","getDoneCount","errorCount","getErrorCount","errorLineCount","getErrorLineCount","isAllComplete","errorLines","getErrorLines","useEffect","setMode","useInput","input","key","toggleErrorFooter","escape","collapse","signalExit","return","toggleExpand","downArrow","scrollDown","EXPANDED_MAX_VISIBLE_LINES","selectNext","upArrow","scrollUp","selectPrev","isActive","visibleProcesses","useMemo","slice","showSelection","Box","flexDirection","Text","Divider","map","item","originalIndex","indexOf","CompactProcessLine","isSelected","id","ExpandedOutput","lines","length","StatusBar","running","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 StatusBar from './StatusBar.ts';\n\ninterface AppProps {\n store: ProcessStore;\n}\n\nfunction AppContent({ store }: AppProps): React.JSX.Element {\n const { exit } = useApp();\n const { isRawModeSupported } = useStdin();\n const { stdout } = useStdout();\n const terminalHeight = stdout?.rows || 24;\n\n // Subscribe to store state\n const processes = useSyncExternalStore(store.subscribe, store.getSnapshot);\n const shouldExit = useSyncExternalStore(store.subscribe, store.getShouldExit);\n const mode = useSyncExternalStore(store.subscribe, store.getMode);\n const selectedIndex = useSyncExternalStore(store.subscribe, store.getSelectedIndex);\n const expandedId = useSyncExternalStore(store.subscribe, store.getExpandedId);\n const scrollOffset = useSyncExternalStore(store.subscribe, store.getScrollOffset);\n const listScrollOffset = useSyncExternalStore(store.subscribe, store.getListScrollOffset);\n const errorFooterExpanded = useSyncExternalStore(store.subscribe, store.getErrorFooterExpanded);\n // Subscribe to buffer version to trigger re-renders when terminal buffer content changes\n const _bufferVersion = useSyncExternalStore(store.subscribe, store.getBufferVersion);\n\n // Subscribed state that triggers re-renders\n const header = useSyncExternalStore(store.subscribe, store.getHeader);\n const showStatusBar = useSyncExternalStore(store.subscribe, store.getShowStatusBar);\n const isInteractive = useSyncExternalStore(store.subscribe, store.getIsInteractive);\n\n // Calculate visible process count (reserve lines for header, divider, status bar, expanded output)\n // When a process is expanded, reserve space for the expanded output to prevent terminal scrolling\n const expandedHeight = expandedId ? EXPANDED_MAX_VISIBLE_LINES + 1 : 0; // +1 for scroll hint\n const reservedLines = (header ? 2 : 0) + (showStatusBar ? 2 : 0) + expandedHeight;\n const visibleProcessCount = Math.max(1, terminalHeight - reservedLines);\n\n // Derived state (computed from processes which is already subscribed)\n const runningCount = store.getRunningCount();\n const doneCount = store.getDoneCount();\n const errorCount = store.getErrorCount();\n const errorLineCount = store.getErrorLineCount();\n const _isAllComplete = store.isAllComplete();\n const errorLines = store.getErrorLines();\n\n // Handle exit signal\n useEffect(() => {\n if (shouldExit) {\n exit();\n }\n }, [shouldExit, exit]);\n\n // Auto-enter interactive mode immediately when interactive flag is set\n // This allows selecting and viewing logs of running processes\n useEffect(() => {\n if (isInteractive && mode === 'normal') {\n store.setMode('interactive');\n }\n }, [isInteractive, mode, store]);\n\n // Keyboard handling (only active when raw mode is supported)\n useInput(\n (input, key) => {\n if (mode === 'normal') {\n // In non-interactive mode, 'e' toggles error footer\n if (input === 'e' && errorCount > 0) {\n store.toggleErrorFooter();\n }\n } else if (mode === 'interactive') {\n if (input === 'q' || key.escape) {\n if (expandedId) {\n store.collapse();\n } else {\n store.signalExit(() => {});\n }\n } else if (key.return) {\n store.toggleExpand();\n } else if (key.downArrow) {\n if (expandedId) {\n store.scrollDown(EXPANDED_MAX_VISIBLE_LINES);\n } else {\n store.selectNext(visibleProcessCount);\n }\n } else if (key.upArrow) {\n if (expandedId) {\n store.scrollUp();\n } else {\n store.selectPrev(visibleProcessCount);\n }\n } else if (input === 'j') {\n if (expandedId) {\n store.scrollDown(EXPANDED_MAX_VISIBLE_LINES);\n } else {\n store.selectNext(visibleProcessCount);\n }\n } else if (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 HEIGHT changes (not content)\n // Combined with incrementalRendering: false in session.tsx, this ensures clean redraws\n // Note: scrollOffset is NOT included - scrolling within expansion doesn't change height\n const layoutKey = `${listScrollOffset}-${expandedId}-${errorCount}-${errorFooterExpanded}`;\n\n return (\n <Box key={layoutKey} flexDirection=\"column\" height={terminalHeight}>\n {/* Header */}\n {header && (\n <>\n <Text>{header}</Text>\n <Divider />\n </>\n )}\n\n {/* Visible processes */}\n <Box flexDirection=\"column\">\n {visibleProcesses.map((item) => {\n const originalIndex = processes.indexOf(item);\n return (\n <Box key={item.id} flexDirection=\"column\">\n <CompactProcessLine item={item} isSelected={showSelection && originalIndex === selectedIndex} />\n {expandedId === item.id && <ExpandedOutput lines={store.getProcessLines(item.id)} scrollOffset={scrollOffset} />}\n </Box>\n );\n })}\n </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","AppContent","store","exit","useApp","isRawModeSupported","useStdin","stdout","useStdout","terminalHeight","rows","processes","useSyncExternalStore","subscribe","getSnapshot","shouldExit","getShouldExit","mode","getMode","selectedIndex","getSelectedIndex","expandedId","getExpandedId","scrollOffset","getScrollOffset","listScrollOffset","getListScrollOffset","errorFooterExpanded","getErrorFooterExpanded","_bufferVersion","getBufferVersion","header","getHeader","showStatusBar","getShowStatusBar","isInteractive","getIsInteractive","expandedHeight","EXPANDED_MAX_VISIBLE_LINES","reservedLines","visibleProcessCount","Math","max","runningCount","getRunningCount","doneCount","getDoneCount","errorCount","getErrorCount","errorLineCount","getErrorLineCount","_isAllComplete","isAllComplete","errorLines","getErrorLines","useEffect","setMode","useInput","input","key","toggleErrorFooter","escape","collapse","signalExit","return","toggleExpand","downArrow","scrollDown","selectNext","upArrow","scrollUp","selectPrev","isActive","visibleProcesses","useMemo","slice","showSelection","layoutKey","Box","flexDirection","height","Text","Divider","map","item","originalIndex","indexOf","CompactProcessLine","isSelected","id","ExpandedOutput","lines","getProcessLines","length","StatusBar","running","done","errors","ErrorFooter","isExpanded","StoreContext","Provider","value"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/OpenSource/node/spawn-term/src/index-esm.ts"],"sourcesContent":["export { default as figures } from './lib/figures.ts';\nexport { default as formatArguments } from './lib/formatArguments.ts';\nexport * from './types.ts';\n\nimport type { createSession as createSessionType, Session } from './createSessionWrapper.ts';\nexport type { Session };\n\nconst major = +process.versions.node.split('.')[0];\n\nimport { createSession as createSessionImpl } from './createSessionWrapper.ts';\nexport const createSession = major > 18 ? createSessionImpl : (undefined as typeof createSessionType);\n"],"names":["createSession","figures","formatArguments","major","process","versions","node","split","createSessionImpl","undefined"],"mappings":";;;;;;;;;;;QAUaA;eAAAA;;QAVOC;eAAAA,kBAAO;;QACPC;eAAAA,0BAAe;;;gEADA;wEACQ;qBAC7B;sCAOqC;;;;;;;;;;;;;;;;;;;AAFnD,IAAMC,QAAQ,CAACC,QAAQC,QAAQ,CAACC,IAAI,CAACC,KAAK,CAAC,IAAI,CAAC,EAAE;AAG3C,IAAMP,gBAAgBG,QAAQ,KAAKK,qCAAiB,GAAIC"}
1
+ {"version":3,"sources":["/Users/kevin/Dev/OpenSource/node/spawn-term/src/index-esm.ts"],"sourcesContent":["export { default as figures } from './lib/figures.ts';\nexport { default as formatArguments } from './lib/formatArguments.ts';\nexport type { TerminalBuffer } from './lib/TerminalBuffer.ts';\nexport * from './types.ts';\n\nimport type { createSession as createSessionType, Session } from './createSessionWrapper.ts';\nexport type { Session };\n\nconst major = +process.versions.node.split('.')[0];\n\nimport { createSession as createSessionImpl } from './createSessionWrapper.ts';\nexport const createSession = major > 18 ? createSessionImpl : (undefined as typeof createSessionType);\n"],"names":["createSession","figures","formatArguments","major","process","versions","node","split","createSessionImpl","undefined"],"mappings":";;;;;;;;;;;QAWaA;eAAAA;;QAXOC;eAAAA,kBAAO;;QACPC;eAAAA,0BAAe;;;gEADA;wEACQ;qBAE7B;sCAOqC;;;;;;;;;;;;;;;;;;;AAFnD,IAAMC,QAAQ,CAACC,QAAQC,QAAQ,CAACC,IAAI,CAACC,KAAK,CAAC,IAAI,CAAC,EAAE;AAG3C,IAAMP,gBAAgBG,QAAQ,KAAKK,qCAAiB,GAAIC"}
@@ -0,0 +1,139 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ Object.defineProperty(exports, "TerminalBuffer", {
6
+ enumerable: true,
7
+ get: function() {
8
+ return TerminalBuffer;
9
+ }
10
+ });
11
+ var _headless = /*#__PURE__*/ _interop_require_wildcard(require("@xterm/headless"));
12
+ function _class_call_check(instance, Constructor) {
13
+ if (!(instance instanceof Constructor)) {
14
+ throw new TypeError("Cannot call a class as a function");
15
+ }
16
+ }
17
+ function _defineProperties(target, props) {
18
+ for(var i = 0; i < props.length; i++){
19
+ var descriptor = props[i];
20
+ descriptor.enumerable = descriptor.enumerable || false;
21
+ descriptor.configurable = true;
22
+ if ("value" in descriptor) descriptor.writable = true;
23
+ Object.defineProperty(target, descriptor.key, descriptor);
24
+ }
25
+ }
26
+ function _create_class(Constructor, protoProps, staticProps) {
27
+ if (protoProps) _defineProperties(Constructor.prototype, protoProps);
28
+ if (staticProps) _defineProperties(Constructor, staticProps);
29
+ return Constructor;
30
+ }
31
+ function _getRequireWildcardCache(nodeInterop) {
32
+ if (typeof WeakMap !== "function") return null;
33
+ var cacheBabelInterop = new WeakMap();
34
+ var cacheNodeInterop = new WeakMap();
35
+ return (_getRequireWildcardCache = function(nodeInterop) {
36
+ return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
37
+ })(nodeInterop);
38
+ }
39
+ function _interop_require_wildcard(obj, nodeInterop) {
40
+ if (!nodeInterop && obj && obj.__esModule) {
41
+ return obj;
42
+ }
43
+ if (obj === null || typeof obj !== "object" && typeof obj !== "function") {
44
+ return {
45
+ default: obj
46
+ };
47
+ }
48
+ var cache = _getRequireWildcardCache(nodeInterop);
49
+ if (cache && cache.has(obj)) {
50
+ return cache.get(obj);
51
+ }
52
+ var newObj = {
53
+ __proto__: null
54
+ };
55
+ var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
56
+ for(var key in obj){
57
+ if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) {
58
+ var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;
59
+ if (desc && (desc.get || desc.set)) {
60
+ Object.defineProperty(newObj, key, desc);
61
+ } else {
62
+ newObj[key] = obj[key];
63
+ }
64
+ }
65
+ }
66
+ newObj.default = obj;
67
+ if (cache) {
68
+ cache.set(obj, newObj);
69
+ }
70
+ return newObj;
71
+ }
72
+ var _xterm_default;
73
+ // Handle both ESM and CJS module formats
74
+ var Terminal = _headless.Terminal || ((_xterm_default = _headless.default) === null || _xterm_default === void 0 ? void 0 : _xterm_default.Terminal);
75
+ var TerminalBuffer = /*#__PURE__*/ function() {
76
+ "use strict";
77
+ function TerminalBuffer(cols) {
78
+ var scrollback = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : 10000;
79
+ _class_call_check(this, TerminalBuffer);
80
+ this.terminal = new Terminal({
81
+ cols: cols,
82
+ rows: 50,
83
+ scrollback: scrollback,
84
+ allowProposedApi: true
85
+ });
86
+ }
87
+ var _proto = TerminalBuffer.prototype;
88
+ /**
89
+ * Write raw data to the terminal buffer.
90
+ * The terminal interprets all ANSI sequences automatically.
91
+ */ _proto.write = function write(data) {
92
+ var str = typeof data === 'string' ? data : data.toString('utf8');
93
+ this.terminal.write(str);
94
+ };
95
+ /**
96
+ * Resize the terminal width.
97
+ */ _proto.resize = function resize(cols) {
98
+ this.terminal.resize(cols, this.terminal.rows);
99
+ };
100
+ /**
101
+ * Extract the rendered lines from the terminal buffer.
102
+ * This returns the actual visible content after all ANSI sequences
103
+ * have been processed.
104
+ */ _proto.getLines = function getLines() {
105
+ var buffer = this.terminal.buffer.active;
106
+ var lines = [];
107
+ for(var i = 0; i < buffer.length; i++){
108
+ var line = buffer.getLine(i);
109
+ if (line) {
110
+ // translateToString(trimRight) - trim trailing whitespace
111
+ // Also trim leading whitespace - tools like ncu/npm use cursor positioning
112
+ // which creates lines with leading spaces when interpreted by xterm
113
+ lines.push(line.translateToString(true).trimStart());
114
+ }
115
+ }
116
+ // Trim trailing empty lines
117
+ while(lines.length > 0 && lines[lines.length - 1] === ''){
118
+ lines.pop();
119
+ }
120
+ return lines;
121
+ };
122
+ /**
123
+ * Clean up terminal resources.
124
+ */ _proto.dispose = function dispose() {
125
+ this.terminal.dispose();
126
+ };
127
+ _create_class(TerminalBuffer, [
128
+ {
129
+ key: "lineCount",
130
+ get: /**
131
+ * Get the number of rendered lines.
132
+ */ function get() {
133
+ return this.getLines().length;
134
+ }
135
+ }
136
+ ]);
137
+ return TerminalBuffer;
138
+ }();
139
+ /* 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/lib/TerminalBuffer.ts"],"sourcesContent":["import * as xterm from '@xterm/headless';\n\n// Handle both ESM and CJS module formats\nconst Terminal = (xterm as { Terminal: typeof xterm.Terminal; default?: { Terminal: typeof xterm.Terminal } }).Terminal || (xterm as { default?: { Terminal: typeof xterm.Terminal } }).default?.Terminal;\n\n/**\n * Wrapper around @xterm/headless Terminal that provides a virtual terminal buffer.\n * Interprets ANSI escape sequences (cursor movement, line clearing, etc.) to produce\n * the actual rendered output rather than raw intermediate states.\n */\nexport class TerminalBuffer {\n private terminal: InstanceType<typeof Terminal>;\n\n constructor(cols: number, scrollback = 10000) {\n this.terminal = new Terminal({\n cols,\n rows: 50, // Visible rows (doesn't matter much for headless)\n scrollback,\n allowProposedApi: true,\n });\n }\n\n /**\n * Write raw data to the terminal buffer.\n * The terminal interprets all ANSI sequences automatically.\n */\n write(data: string | Buffer): void {\n const str = typeof data === 'string' ? data : data.toString('utf8');\n this.terminal.write(str);\n }\n\n /**\n * Resize the terminal width.\n */\n resize(cols: number): void {\n this.terminal.resize(cols, this.terminal.rows);\n }\n\n /**\n * Extract the rendered lines from the terminal buffer.\n * This returns the actual visible content after all ANSI sequences\n * have been processed.\n */\n getLines(): string[] {\n const buffer = this.terminal.buffer.active;\n const lines: string[] = [];\n\n for (let i = 0; i < buffer.length; i++) {\n const line = buffer.getLine(i);\n if (line) {\n // translateToString(trimRight) - trim trailing whitespace\n // Also trim leading whitespace - tools like ncu/npm use cursor positioning\n // which creates lines with leading spaces when interpreted by xterm\n lines.push(line.translateToString(true).trimStart());\n }\n }\n\n // Trim trailing empty lines\n while (lines.length > 0 && lines[lines.length - 1] === '') {\n lines.pop();\n }\n\n return lines;\n }\n\n /**\n * Get the number of rendered lines.\n */\n get lineCount(): number {\n return this.getLines().length;\n }\n\n /**\n * Clean up terminal resources.\n */\n dispose(): void {\n this.terminal.dispose();\n }\n}\n"],"names":["TerminalBuffer","Terminal","xterm","default","cols","scrollback","terminal","rows","allowProposedApi","write","data","str","toString","resize","getLines","buffer","active","lines","i","length","line","getLine","push","translateToString","trimStart","pop","dispose","lineCount"],"mappings":";;;;+BAUaA;;;eAAAA;;;gEAVU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAGoG;AAD3H,yCAAyC;AACzC,IAAMC,WAAW,AAACC,UAA6FD,QAAQ,MAAI,iBAAA,AAACC,UAA4DC,OAAO,cAApE,qCAAA,eAAsEF,QAAQ;AAOlM,IAAA,AAAMD,+BAAN;;aAAMA,eAGCI,IAAY;YAAEC,aAAAA,iEAAa;gCAH5BL;QAIT,IAAI,CAACM,QAAQ,GAAG,IAAIL,SAAS;YAC3BG,MAAAA;YACAG,MAAM;YACNF,YAAAA;YACAG,kBAAkB;QACpB;;iBATSR;IAYX;;;GAGC,GACDS,OAAAA,KAGC,GAHDA,SAAAA,MAAMC,IAAqB;QACzB,IAAMC,MAAM,OAAOD,SAAS,WAAWA,OAAOA,KAAKE,QAAQ,CAAC;QAC5D,IAAI,CAACN,QAAQ,CAACG,KAAK,CAACE;IACtB;IAEA;;GAEC,GACDE,OAAAA,MAEC,GAFDA,SAAAA,OAAOT,IAAY;QACjB,IAAI,CAACE,QAAQ,CAACO,MAAM,CAACT,MAAM,IAAI,CAACE,QAAQ,CAACC,IAAI;IAC/C;IAEA;;;;GAIC,GACDO,OAAAA,QAoBC,GApBDA,SAAAA;QACE,IAAMC,SAAS,IAAI,CAACT,QAAQ,CAACS,MAAM,CAACC,MAAM;QAC1C,IAAMC,QAAkB,EAAE;QAE1B,IAAK,IAAIC,IAAI,GAAGA,IAAIH,OAAOI,MAAM,EAAED,IAAK;YACtC,IAAME,OAAOL,OAAOM,OAAO,CAACH;YAC5B,IAAIE,MAAM;gBACR,0DAA0D;gBAC1D,2EAA2E;gBAC3E,oEAAoE;gBACpEH,MAAMK,IAAI,CAACF,KAAKG,iBAAiB,CAAC,MAAMC,SAAS;YACnD;QACF;QAEA,4BAA4B;QAC5B,MAAOP,MAAME,MAAM,GAAG,KAAKF,KAAK,CAACA,MAAME,MAAM,GAAG,EAAE,KAAK,GAAI;YACzDF,MAAMQ,GAAG;QACX;QAEA,OAAOR;IACT;IASA;;GAEC,GACDS,OAAAA,OAEC,GAFDA,SAAAA;QACE,IAAI,CAACpB,QAAQ,CAACoB,OAAO;IACvB;kBAnEW1B;;YA0DP2B,KAAAA;iBAAJ,AAHA;;GAEC,GACD;gBACE,OAAO,IAAI,CAACb,QAAQ,GAAGK,MAAM;YAC/B;;;WA5DWnB"}
@@ -16,16 +16,28 @@ var _onone = /*#__PURE__*/ _interop_require_default(require("on-one"));
16
16
  var _queuecb = /*#__PURE__*/ _interop_require_default(require("queue-cb"));
17
17
  var _Appts = /*#__PURE__*/ _interop_require_default(require("./components/App.js"));
18
18
  var _constantsts = require("./constants.js");
19
- var _addLinests = /*#__PURE__*/ _interop_require_default(require("./lib/addLines.js"));
20
19
  var _concatWritablets = /*#__PURE__*/ _interop_require_default(require("./lib/concatWritable.js"));
21
20
  var _formatArgumentsts = /*#__PURE__*/ _interop_require_default(require("./lib/formatArguments.js"));
21
+ var _TerminalBufferts = require("./lib/TerminalBuffer.js");
22
22
  var _processStorets = require("./state/processStore.js");
23
- var _typests = require("./types.js");
24
23
  function _class_call_check(instance, Constructor) {
25
24
  if (!(instance instanceof Constructor)) {
26
25
  throw new TypeError("Cannot call a class as a function");
27
26
  }
28
27
  }
28
+ function _define_property(obj, key, value) {
29
+ if (key in obj) {
30
+ Object.defineProperty(obj, key, {
31
+ value: value,
32
+ enumerable: true,
33
+ configurable: true,
34
+ writable: true
35
+ });
36
+ } else {
37
+ obj[key] = value;
38
+ }
39
+ return obj;
40
+ }
29
41
  function _interop_require_default(obj) {
30
42
  return obj && obj.__esModule ? obj : {
31
43
  default: obj
@@ -72,6 +84,45 @@ function _interop_require_wildcard(obj, nodeInterop) {
72
84
  }
73
85
  return newObj;
74
86
  }
87
+ function _object_spread(target) {
88
+ for(var i = 1; i < arguments.length; i++){
89
+ var source = arguments[i] != null ? arguments[i] : {};
90
+ var ownKeys = Object.keys(source);
91
+ if (typeof Object.getOwnPropertySymbols === "function") {
92
+ ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function(sym) {
93
+ return Object.getOwnPropertyDescriptor(source, sym).enumerable;
94
+ }));
95
+ }
96
+ ownKeys.forEach(function(key) {
97
+ _define_property(target, key, source[key]);
98
+ });
99
+ }
100
+ return target;
101
+ }
102
+ function ownKeys(object, enumerableOnly) {
103
+ var keys = Object.keys(object);
104
+ if (Object.getOwnPropertySymbols) {
105
+ var symbols = Object.getOwnPropertySymbols(object);
106
+ if (enumerableOnly) {
107
+ symbols = symbols.filter(function(sym) {
108
+ return Object.getOwnPropertyDescriptor(object, sym).enumerable;
109
+ });
110
+ }
111
+ keys.push.apply(keys, symbols);
112
+ }
113
+ return keys;
114
+ }
115
+ function _object_spread_props(target, source) {
116
+ source = source != null ? source : {};
117
+ if (Object.getOwnPropertyDescriptors) {
118
+ Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
119
+ } else {
120
+ ownKeys(Object(source)).forEach(function(key) {
121
+ Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
122
+ });
123
+ }
124
+ return target;
125
+ }
75
126
  function _object_without_properties(source, excluded) {
76
127
  if (source == null) return {};
77
128
  var target = _object_without_properties_loose(source, excluded);
@@ -111,13 +162,21 @@ var SessionImpl = /*#__PURE__*/ function() {
111
162
  this.store = new _processStorets.ProcessStore(options);
112
163
  var _options_interactive;
113
164
  this.isInteractive = (_options_interactive = options.interactive) !== null && _options_interactive !== void 0 ? _options_interactive : false;
114
- // Render Ink app immediately
115
- this.inkApp = (0, _ink.render)(/*#__PURE__*/ (0, _jsxruntime.jsx)(_Appts.default, {
116
- store: this.store
117
- }), {
118
- incrementalRendering: true,
119
- maxFps: _constantsts.DEFAULT_MAX_FPS
120
- });
165
+ // Use a very wide buffer to prevent line wrapping in xterm
166
+ // Actual display truncation is handled by Ink components
167
+ this.terminalWidth = 10000;
168
+ // Only render Ink when stdout is a real terminal
169
+ // When piped (e.g., nested spawn-term), skip Ink to avoid cursor positioning artifacts
170
+ if (process.stdout.isTTY) {
171
+ // Note: incrementalRendering disabled to prevent corruption when content shifts vertically
172
+ // (e.g., error footer appearing, processes completing, scroll position changes)
173
+ this.inkApp = (0, _ink.render)(/*#__PURE__*/ (0, _jsxruntime.jsx)(_Appts.default, {
174
+ store: this.store
175
+ }), {
176
+ incrementalRendering: false,
177
+ maxFps: _constantsts.DEFAULT_MAX_FPS
178
+ });
179
+ }
121
180
  }
122
181
  var _proto = SessionImpl.prototype;
123
182
  _proto.spawn = function spawn(command, args, spawnOptions, options, callback) {
@@ -130,8 +189,28 @@ var SessionImpl = /*#__PURE__*/ function() {
130
189
  "stdio"
131
190
  ]);
132
191
  if (stdio === 'inherit') {
192
+ // When Ink is not rendering (stdout not a TTY), pass output directly to stdout
193
+ if (!this.inkApp) {
194
+ var cp = (0, _crossspawncb.crossSpawn)(command, args, _object_spread_props(_object_spread({}, csOptions), {
195
+ stdio: 'inherit'
196
+ }));
197
+ _crossspawncb.default.worker(cp, csOptions, function(err) {
198
+ var res = err ? err : {};
199
+ res.stdout = null;
200
+ res.stderr = null;
201
+ res.output = [
202
+ null,
203
+ null,
204
+ null
205
+ ];
206
+ err ? callback(err) : callback(null, res);
207
+ });
208
+ return;
209
+ }
133
210
  this.runningCount++;
134
211
  var id = _crypto.default.randomUUID();
212
+ // Create terminal buffer for ANSI sequence interpretation
213
+ var terminalBuffer = new _TerminalBufferts.TerminalBuffer(this.terminalWidth);
135
214
  this.store.addProcess({
136
215
  id: id,
137
216
  title: [
@@ -139,55 +218,49 @@ var SessionImpl = /*#__PURE__*/ function() {
139
218
  ].concat((0, _formatArgumentsts.default)(args)).join(' '),
140
219
  state: 'running',
141
220
  lines: [],
221
+ terminalBuffer: terminalBuffer,
142
222
  group: options.group,
143
223
  expanded: options.expanded
144
224
  });
145
- var cp = (0, _crossspawncb.crossSpawn)(command, args, csOptions);
146
- var outputs = {
147
- stdout: null,
148
- stderr: null
149
- };
150
- var queue = new _queuecb.default();
151
- if (cp.stdout) {
152
- outputs.stdout = (0, _addLinests.default)(function(lines) {
153
- _this.store.appendLines(id, lines.map(function(text) {
154
- return {
155
- type: _typests.LineType.stdout,
156
- text: text
157
- };
158
- }));
225
+ var cp1 = (0, _crossspawncb.crossSpawn)(command, args, csOptions);
226
+ // Pipe stdout and stderr directly to terminal buffer
227
+ // Both streams go to the same buffer to maintain correct ordering
228
+ if (cp1.stdout) {
229
+ cp1.stdout.on('data', function(chunk) {
230
+ terminalBuffer.write(chunk);
231
+ _this.store.notify();
159
232
  });
160
- queue.defer(_onone.default.bind(null, cp.stdout.pipe(outputs.stdout), [
233
+ }
234
+ if (cp1.stderr) {
235
+ cp1.stderr.on('data', function(chunk) {
236
+ terminalBuffer.write(chunk);
237
+ _this.store.notify();
238
+ });
239
+ }
240
+ // Wait for process to complete
241
+ var queue = new _queuecb.default();
242
+ if (cp1.stdout) {
243
+ queue.defer(_onone.default.bind(null, cp1.stdout, [
161
244
  'error',
162
245
  'end',
163
- 'close',
164
- 'finish'
246
+ 'close'
165
247
  ]));
166
248
  }
167
- if (cp.stderr) {
168
- outputs.stderr = (0, _addLinests.default)(function(lines) {
169
- _this.store.appendLines(id, lines.map(function(text) {
170
- return {
171
- type: _typests.LineType.stderr,
172
- text: text
173
- };
174
- }));
175
- });
176
- queue.defer(_onone.default.bind(null, cp.stderr.pipe(outputs.stderr), [
249
+ if (cp1.stderr) {
250
+ queue.defer(_onone.default.bind(null, cp1.stderr, [
177
251
  'error',
178
252
  'end',
179
- 'close',
180
- 'finish'
253
+ 'close'
181
254
  ]));
182
255
  }
183
- queue.defer(_crossspawncb.default.worker.bind(null, cp, csOptions));
256
+ queue.defer(_crossspawncb.default.worker.bind(null, cp1, csOptions));
184
257
  queue.await(function(err) {
185
258
  var res = err ? err : {};
186
- res.stdout = outputs.stdout ? outputs.stdout.output : null;
187
- res.stderr = outputs.stderr ? outputs.stderr.output : null;
259
+ res.stdout = null; // Not collecting raw output in inherit mode
260
+ res.stderr = null;
188
261
  res.output = [
189
- res.stdout,
190
- res.stderr,
262
+ null,
263
+ null,
191
264
  null
192
265
  ];
193
266
  _this.store.updateProcess(id, {
@@ -198,39 +271,39 @@ var SessionImpl = /*#__PURE__*/ function() {
198
271
  });
199
272
  } else {
200
273
  // Non-inherit mode: collect output but don't display in UI
201
- var cp1 = (0, _crossspawncb.crossSpawn)(command, args, csOptions);
202
- var outputs1 = {
274
+ var cp2 = (0, _crossspawncb.crossSpawn)(command, args, csOptions);
275
+ var outputs = {
203
276
  stdout: null,
204
277
  stderr: null
205
278
  };
206
279
  var queue1 = new _queuecb.default();
207
- if (cp1.stdout) {
208
- outputs1.stdout = (0, _concatWritablets.default)(function(output) {
209
- outputs1.stdout.output = output.toString(encoding || 'utf8');
280
+ if (cp2.stdout) {
281
+ outputs.stdout = (0, _concatWritablets.default)(function(output) {
282
+ outputs.stdout.output = output.toString(encoding || 'utf8');
210
283
  });
211
- queue1.defer(_onone.default.bind(null, cp1.stdout.pipe(outputs1.stdout), [
284
+ queue1.defer(_onone.default.bind(null, cp2.stdout.pipe(outputs.stdout), [
212
285
  'error',
213
286
  'end',
214
287
  'close',
215
288
  'finish'
216
289
  ]));
217
290
  }
218
- if (cp1.stderr) {
219
- outputs1.stderr = (0, _concatWritablets.default)(function(output) {
220
- outputs1.stderr.output = output.toString(encoding || 'utf8');
291
+ if (cp2.stderr) {
292
+ outputs.stderr = (0, _concatWritablets.default)(function(output) {
293
+ outputs.stderr.output = output.toString(encoding || 'utf8');
221
294
  });
222
- queue1.defer(_onone.default.bind(null, cp1.stderr.pipe(outputs1.stderr), [
295
+ queue1.defer(_onone.default.bind(null, cp2.stderr.pipe(outputs.stderr), [
223
296
  'error',
224
297
  'end',
225
298
  'close',
226
299
  'finish'
227
300
  ]));
228
301
  }
229
- queue1.defer(_crossspawncb.default.worker.bind(null, cp1, csOptions));
302
+ queue1.defer(_crossspawncb.default.worker.bind(null, cp2, csOptions));
230
303
  queue1.await(function(err) {
231
304
  var res = err ? err : {};
232
- res.stdout = outputs1.stdout ? outputs1.stdout.output : null;
233
- res.stderr = outputs1.stderr ? outputs1.stderr.output : null;
305
+ res.stdout = outputs.stdout ? outputs.stdout.output : null;
306
+ res.stderr = outputs.stderr ? outputs.stderr.output : null;
234
307
  res.output = [
235
308
  res.stdout,
236
309
  res.stderr,