spawn-term 3.5.1 → 3.5.3

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.
@@ -86,7 +86,7 @@ var RunningSummary = /*#__PURE__*/ (0, _react.memo)(function RunningSummary(para
86
86
  return /*#__PURE__*/ (0, _jsxruntime.jsx)(_ink.Box, {
87
87
  marginLeft: 2,
88
88
  children: /*#__PURE__*/ (0, _jsxruntime.jsx)(_ink.Text, {
89
- children: line.text
89
+ children: line.text || ' '
90
90
  })
91
91
  });
92
92
  });
@@ -94,7 +94,7 @@ var renderLine = function(line, index) {
94
94
  return /*#__PURE__*/ (0, _jsxruntime.jsx)(_ink.Box, {
95
95
  minHeight: 1,
96
96
  children: /*#__PURE__*/ (0, _jsxruntime.jsx)(_ink.Text, {
97
- children: line.text
97
+ children: line.text || ' '
98
98
  })
99
99
  }, index);
100
100
  };
@@ -136,11 +136,10 @@ var Contracted = /*#__PURE__*/ (0, _react.memo)(function Contracted(param) {
136
136
  ]);
137
137
  var summary = (0, _react.useMemo)(function() {
138
138
  return lines.filter(function(line) {
139
- return line.text.length > 0 && errors.indexOf(line) < 0;
139
+ return line.type !== _typests.LineType.stderr && line.text.length > 0;
140
140
  }).pop();
141
141
  }, [
142
- lines,
143
- errors
142
+ lines
144
143
  ]);
145
144
  return /*#__PURE__*/ (0, _jsxruntime.jsxs)(_ink.Box, {
146
145
  flexDirection: "column",
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/OpenSource/node/spawn-term/src/components/ChildProcess.tsx"],"sourcesContent":["import { Box, Text } from 'ink';\nimport { memo, useMemo } from 'react';\nimport { SPINNER } from '../constants.ts';\nimport figures from '../lib/figures.ts';\nimport type { ChildProcess as ChildProcessT, Line, State } from '../types.ts';\nimport { LineType } from '../types.ts';\nimport Spinner from './Spinner.ts';\n\nconst BLANK_LINE = { type: LineType.stdout, text: '' };\n\nconst ICONS = {\n error: <Text color=\"red\">{figures.cross}</Text>,\n success: <Text color=\"green\">{figures.tick}</Text>,\n running: <Spinner {...SPINNER} />,\n};\n\ntype ItemProps = {\n item: ChildProcessT;\n};\n\ntype HeaderProps = {\n group?: string;\n title: string;\n state: State;\n};\n\nconst Header = memo(\n function Header({ group, title, state }: HeaderProps) {\n const icon = ICONS[state];\n\n return (\n <Box>\n {icon}\n {group && <Text bold>{`${group}${figures.pointer} `}</Text>}\n <Text>{title}</Text>\n </Box>\n );\n },\n (a, b) => a.group === b.group && a.title === b.title && a.state === b.state\n);\n\ntype RunningSummaryProps = {\n line: Line;\n};\n\nconst RunningSummary = memo(function RunningSummary({ line }: RunningSummaryProps) {\n return (\n <Box marginLeft={2}>\n <Text>{line.text}</Text>\n </Box>\n );\n});\n\ntype LinesProps = {\n lines: Line[];\n};\n\nconst renderLine = (line, index) => {\n return (\n <Box key={index} minHeight={1}>\n <Text>{line.text}</Text>\n </Box>\n );\n};\n\nconst Lines = memo(function Lines({ lines }: LinesProps) {\n return (\n <Box flexDirection=\"column\" marginLeft={2}>\n {lines.map(renderLine)}\n </Box>\n );\n});\n\nconst Expanded = memo(function Expanded({ item }: ItemProps) {\n const { lines } = item;\n\n return (\n <Box flexDirection=\"column\">\n <Header group={item.group} title={item.title} state={item.state} />\n <Lines lines={lines} />\n </Box>\n );\n});\n\nconst Contracted = memo(function Contracted({ item }: ItemProps) {\n const { state, lines } = item;\n\n // remove ansi codes when displaying single lines\n const errors = useMemo(() => lines.filter((line) => line.type === LineType.stderr), [lines]);\n const summary = useMemo(() => lines.filter((line) => line.text.length > 0 && errors.indexOf(line) < 0).pop(), [lines, errors]);\n\n return (\n <Box flexDirection=\"column\">\n <Header group={item.group} title={item.title} state={item.state} />\n {state === 'running' && <RunningSummary line={summary || BLANK_LINE} />}\n {errors.length > 0 && <Lines lines={errors} />}\n </Box>\n );\n});\n\nexport default memo(function ChildProcess({ item }: ItemProps) {\n const { expanded } = item;\n return expanded ? <Expanded item={item} /> : <Contracted item={item} />;\n});\n"],"names":["BLANK_LINE","type","LineType","stdout","text","ICONS","error","Text","color","figures","cross","success","tick","running","Spinner","SPINNER","Header","memo","group","title","state","icon","Box","bold","pointer","a","b","RunningSummary","line","marginLeft","renderLine","index","minHeight","Lines","lines","flexDirection","map","Expanded","item","Contracted","errors","useMemo","filter","stderr","summary","length","indexOf","pop","ChildProcess","expanded"],"mappings":"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"}
1
+ {"version":3,"sources":["/Users/kevin/Dev/OpenSource/node/spawn-term/src/components/ChildProcess.tsx"],"sourcesContent":["import { Box, Text } from 'ink';\nimport { memo, useMemo } from 'react';\nimport { SPINNER } from '../constants.ts';\nimport figures from '../lib/figures.ts';\nimport type { ChildProcess as ChildProcessT, Line, State } from '../types.ts';\nimport { LineType } from '../types.ts';\nimport Spinner from './Spinner.ts';\n\nconst BLANK_LINE = { type: LineType.stdout, text: '' };\n\nconst ICONS = {\n error: <Text color=\"red\">{figures.cross}</Text>,\n success: <Text color=\"green\">{figures.tick}</Text>,\n running: <Spinner {...SPINNER} />,\n};\n\ntype ItemProps = {\n item: ChildProcessT;\n};\n\ntype HeaderProps = {\n group?: string;\n title: string;\n state: State;\n};\n\nconst Header = memo(\n function Header({ group, title, state }: HeaderProps) {\n const icon = ICONS[state];\n\n return (\n <Box>\n {icon}\n {group && <Text bold>{`${group}${figures.pointer} `}</Text>}\n <Text>{title}</Text>\n </Box>\n );\n },\n (a, b) => a.group === b.group && a.title === b.title && a.state === b.state\n);\n\ntype RunningSummaryProps = {\n line: Line;\n};\n\nconst RunningSummary = memo(function RunningSummary({ line }: RunningSummaryProps) {\n return (\n <Box marginLeft={2}>\n <Text>{line.text || ' '}</Text>\n </Box>\n );\n});\n\ntype LinesProps = {\n lines: Line[];\n};\n\nconst renderLine = (line, index) => {\n return (\n <Box key={index} minHeight={1}>\n <Text>{line.text || ' '}</Text>\n </Box>\n );\n};\n\nconst Lines = memo(function Lines({ lines }: LinesProps) {\n return (\n <Box flexDirection=\"column\" marginLeft={2}>\n {lines.map(renderLine)}\n </Box>\n );\n});\n\nconst Expanded = memo(function Expanded({ item }: ItemProps) {\n const { lines } = item;\n\n return (\n <Box flexDirection=\"column\">\n <Header group={item.group} title={item.title} state={item.state} />\n <Lines lines={lines} />\n </Box>\n );\n});\n\nconst Contracted = memo(function Contracted({ item }: ItemProps) {\n const { state, lines } = item;\n\n // remove ansi codes when displaying single lines\n const errors = useMemo(() => lines.filter((line) => line.type === LineType.stderr), [lines]);\n const summary = useMemo(() => lines.filter((line) => line.type !== LineType.stderr && line.text.length > 0).pop(), [lines]);\n\n return (\n <Box flexDirection=\"column\">\n <Header group={item.group} title={item.title} state={item.state} />\n {state === 'running' && <RunningSummary line={summary || BLANK_LINE} />}\n {errors.length > 0 && <Lines lines={errors} />}\n </Box>\n );\n});\n\nexport default memo(function ChildProcess({ item }: ItemProps) {\n const { expanded } = item;\n return expanded ? <Expanded item={item} /> : <Contracted item={item} />;\n});\n"],"names":["BLANK_LINE","type","LineType","stdout","text","ICONS","error","Text","color","figures","cross","success","tick","running","Spinner","SPINNER","Header","memo","group","title","state","icon","Box","bold","pointer","a","b","RunningSummary","line","marginLeft","renderLine","index","minHeight","Lines","lines","flexDirection","map","Expanded","item","Contracted","errors","useMemo","filter","stderr","summary","length","pop","ChildProcess","expanded"],"mappings":"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"}
@@ -99,8 +99,9 @@ var _default = /*#__PURE__*/ (0, _react.memo)(function ErrorFooter(param) {
99
99
  "]"
100
100
  ]
101
101
  }),
102
- " ",
103
- line.text
102
+ /*#__PURE__*/ (0, _jsxruntime.jsx)(_ink.Text, {
103
+ children: " ".concat(line.text)
104
+ })
104
105
  ]
105
106
  }, "".concat(errorGroup.processName, "-").concat(index));
106
107
  });
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/OpenSource/node/spawn-term/src/components/ErrorFooter.tsx"],"sourcesContent":["import { Box, Text } from 'ink';\nimport { memo } from 'react';\nimport type { Line } from '../types.ts';\nimport { LineType } from '../types.ts';\nimport Divider from './Divider.ts';\n\ntype ErrorGroup = {\n processName: string;\n lines: Line[];\n};\n\ntype Props = {\n errors: ErrorGroup[];\n isExpanded: boolean;\n};\n\nexport default memo(function ErrorFooter({ errors, isExpanded }: Props) {\n // Calculate totals for collapsed summary\n const totalLines = errors.reduce((sum, e) => sum + e.lines.filter((l) => l.type === LineType.stderr).length, 0);\n const totalProcesses = errors.length;\n\n if (totalProcesses === 0) {\n return null;\n }\n\n const processText = totalProcesses === 1 ? 'process' : 'processes';\n\n if (!isExpanded) {\n // Collapsed view - single summary line\n const summary = totalLines > 0 ? `${totalLines} error line${totalLines === 1 ? '' : 's'} in ${totalProcesses} ${processText}` : `${totalProcesses} failed ${processText}`;\n return (\n <>\n <Divider />\n <Text>\n <Text color=\"red\">{'\\u25b8'}</Text>\n {` ${summary}`}\n </Text>\n </>\n );\n }\n\n // Expanded view - show all error lines (or just process names if no stderr)\n return (\n <>\n <Divider />\n <Text>\n <Text color=\"red\">{'\\u25be'}</Text>\n {' Errors'}\n </Text>\n <Box flexDirection=\"column\">\n {errors.map((errorGroup) => {\n const stderrLines = errorGroup.lines.filter((line) => line.type === LineType.stderr);\n if (stderrLines.length === 0) {\n // No stderr output - just show process name\n return (\n <Text key={errorGroup.processName}>\n <Text dimColor>[{errorGroup.processName}]</Text> <Text color=\"red\">(failed)</Text>\n </Text>\n );\n }\n return stderrLines.map((line, index) => (\n <Text key={`${errorGroup.processName}-${index}`}>\n <Text dimColor>[{errorGroup.processName}]</Text> {line.text}\n </Text>\n ));\n })}\n </Box>\n </>\n );\n});\n"],"names":["memo","ErrorFooter","errors","isExpanded","totalLines","reduce","sum","e","lines","filter","l","type","LineType","stderr","length","totalProcesses","processText","summary","Divider","Text","color","Box","flexDirection","map","errorGroup","stderrLines","line","dimColor","processName","index","text"],"mappings":";;;;+BAgBA;;;eAAA;;;;mBAhB0B;qBACL;uBAEI;gEACL;;;;;;IAYpB,yBAAeA,IAAAA,WAAI,EAAC,SAASC,YAAY,KAA6B;QAA3BC,SAAF,MAAEA,QAAQC,aAAV,MAAUA;IACjD,yCAAyC;IACzC,IAAMC,aAAaF,OAAOG,MAAM,CAAC,SAACC,KAAKC;eAAMD,MAAMC,EAAEC,KAAK,CAACC,MAAM,CAAC,SAACC;mBAAMA,EAAEC,IAAI,KAAKC,iBAAQ,CAACC,MAAM;WAAEC,MAAM;OAAE;IAC7G,IAAMC,iBAAiBb,OAAOY,MAAM;IAEpC,IAAIC,mBAAmB,GAAG;QACxB,OAAO;IACT;IAEA,IAAMC,cAAcD,mBAAmB,IAAI,YAAY;IAEvD,IAAI,CAACZ,YAAY;QACf,uCAAuC;QACvC,IAAMc,UAAUb,aAAa,IAAI,AAAC,GAA0BA,OAAxBA,YAAW,eAA+CW,OAAlCX,eAAe,IAAI,KAAK,KAAI,QAAwBY,OAAlBD,gBAAe,KAAe,OAAZC,eAAgB,AAAC,GAA2BA,OAAzBD,gBAAe,YAAsB,OAAZC;QAC5J,qBACE;;8BACE,qBAACE,kBAAO;8BACR,sBAACC,SAAI;;sCACH,qBAACA,SAAI;4BAACC,OAAM;sCAAO;;wBACjB,IAAW,OAARH;;;;;IAIb;IAEA,4EAA4E;IAC5E,qBACE;;0BACE,qBAACC,kBAAO;0BACR,sBAACC,SAAI;;kCACH,qBAACA,SAAI;wBAACC,OAAM;kCAAO;;oBAClB;;;0BAEH,qBAACC,QAAG;gBAACC,eAAc;0BAChBpB,OAAOqB,GAAG,CAAC,SAACC;oBACX,IAAMC,cAAcD,WAAWhB,KAAK,CAACC,MAAM,CAAC,SAACiB;+BAASA,KAAKf,IAAI,KAAKC,iBAAQ,CAACC,MAAM;;oBACnF,IAAIY,YAAYX,MAAM,KAAK,GAAG;wBAC5B,4CAA4C;wBAC5C,qBACE,sBAACK,SAAI;;8CACH,sBAACA,SAAI;oCAACQ,QAAQ;;wCAAC;wCAAEH,WAAWI,WAAW;wCAAC;;;gCAAQ;8CAAC,qBAACT,SAAI;oCAACC,OAAM;8CAAM;;;2BAD1DI,WAAWI,WAAW;oBAIrC;oBACA,OAAOH,YAAYF,GAAG,CAAC,SAACG,MAAMG;6CAC5B,sBAACV,SAAI;;8CACH,sBAACA,SAAI;oCAACQ,QAAQ;;wCAAC;wCAAEH,WAAWI,WAAW;wCAAC;;;gCAAQ;gCAAEF,KAAKI,IAAI;;2BADlD,AAAC,GAA4BD,OAA1BL,WAAWI,WAAW,EAAC,KAAS,OAANC;;gBAI5C;;;;AAIR"}
1
+ {"version":3,"sources":["/Users/kevin/Dev/OpenSource/node/spawn-term/src/components/ErrorFooter.tsx"],"sourcesContent":["import { Box, Text } from 'ink';\nimport { memo } from 'react';\nimport type { Line } from '../types.ts';\nimport { LineType } from '../types.ts';\nimport Divider from './Divider.ts';\n\ntype ErrorGroup = {\n processName: string;\n lines: Line[];\n};\n\ntype Props = {\n errors: ErrorGroup[];\n isExpanded: boolean;\n};\n\nexport default memo(function ErrorFooter({ errors, isExpanded }: Props) {\n // Calculate totals for collapsed summary\n const totalLines = errors.reduce((sum, e) => sum + e.lines.filter((l) => l.type === LineType.stderr).length, 0);\n const totalProcesses = errors.length;\n\n if (totalProcesses === 0) {\n return null;\n }\n\n const processText = totalProcesses === 1 ? 'process' : 'processes';\n\n if (!isExpanded) {\n // Collapsed view - single summary line\n const summary = totalLines > 0 ? `${totalLines} error line${totalLines === 1 ? '' : 's'} in ${totalProcesses} ${processText}` : `${totalProcesses} failed ${processText}`;\n return (\n <>\n <Divider />\n <Text>\n <Text color=\"red\">{'\\u25b8'}</Text>\n {` ${summary}`}\n </Text>\n </>\n );\n }\n\n // Expanded view - show all error lines (or just process names if no stderr)\n return (\n <>\n <Divider />\n <Text>\n <Text color=\"red\">{'\\u25be'}</Text>\n {' Errors'}\n </Text>\n <Box flexDirection=\"column\">\n {errors.map((errorGroup) => {\n const stderrLines = errorGroup.lines.filter((line) => line.type === LineType.stderr);\n if (stderrLines.length === 0) {\n // No stderr output - just show process name\n return (\n <Text key={errorGroup.processName}>\n <Text dimColor>[{errorGroup.processName}]</Text> <Text color=\"red\">(failed)</Text>\n </Text>\n );\n }\n return stderrLines.map((line, index) => (\n <Text key={`${errorGroup.processName}-${index}`}>\n <Text dimColor>[{errorGroup.processName}]</Text>\n <Text>{` ${line.text}`}</Text>\n </Text>\n ));\n })}\n </Box>\n </>\n );\n});\n"],"names":["memo","ErrorFooter","errors","isExpanded","totalLines","reduce","sum","e","lines","filter","l","type","LineType","stderr","length","totalProcesses","processText","summary","Divider","Text","color","Box","flexDirection","map","errorGroup","stderrLines","line","dimColor","processName","index","text"],"mappings":";;;;+BAgBA;;;eAAA;;;;mBAhB0B;qBACL;uBAEI;gEACL;;;;;;IAYpB,yBAAeA,IAAAA,WAAI,EAAC,SAASC,YAAY,KAA6B;QAA3BC,SAAF,MAAEA,QAAQC,aAAV,MAAUA;IACjD,yCAAyC;IACzC,IAAMC,aAAaF,OAAOG,MAAM,CAAC,SAACC,KAAKC;eAAMD,MAAMC,EAAEC,KAAK,CAACC,MAAM,CAAC,SAACC;mBAAMA,EAAEC,IAAI,KAAKC,iBAAQ,CAACC,MAAM;WAAEC,MAAM;OAAE;IAC7G,IAAMC,iBAAiBb,OAAOY,MAAM;IAEpC,IAAIC,mBAAmB,GAAG;QACxB,OAAO;IACT;IAEA,IAAMC,cAAcD,mBAAmB,IAAI,YAAY;IAEvD,IAAI,CAACZ,YAAY;QACf,uCAAuC;QACvC,IAAMc,UAAUb,aAAa,IAAI,AAAC,GAA0BA,OAAxBA,YAAW,eAA+CW,OAAlCX,eAAe,IAAI,KAAK,KAAI,QAAwBY,OAAlBD,gBAAe,KAAe,OAAZC,eAAgB,AAAC,GAA2BA,OAAzBD,gBAAe,YAAsB,OAAZC;QAC5J,qBACE;;8BACE,qBAACE,kBAAO;8BACR,sBAACC,SAAI;;sCACH,qBAACA,SAAI;4BAACC,OAAM;sCAAO;;wBACjB,IAAW,OAARH;;;;;IAIb;IAEA,4EAA4E;IAC5E,qBACE;;0BACE,qBAACC,kBAAO;0BACR,sBAACC,SAAI;;kCACH,qBAACA,SAAI;wBAACC,OAAM;kCAAO;;oBAClB;;;0BAEH,qBAACC,QAAG;gBAACC,eAAc;0BAChBpB,OAAOqB,GAAG,CAAC,SAACC;oBACX,IAAMC,cAAcD,WAAWhB,KAAK,CAACC,MAAM,CAAC,SAACiB;+BAASA,KAAKf,IAAI,KAAKC,iBAAQ,CAACC,MAAM;;oBACnF,IAAIY,YAAYX,MAAM,KAAK,GAAG;wBAC5B,4CAA4C;wBAC5C,qBACE,sBAACK,SAAI;;8CACH,sBAACA,SAAI;oCAACQ,QAAQ;;wCAAC;wCAAEH,WAAWI,WAAW;wCAAC;;;gCAAQ;8CAAC,qBAACT,SAAI;oCAACC,OAAM;8CAAM;;;2BAD1DI,WAAWI,WAAW;oBAIrC;oBACA,OAAOH,YAAYF,GAAG,CAAC,SAACG,MAAMG;6CAC5B,sBAACV,SAAI;;8CACH,sBAACA,SAAI;oCAACQ,QAAQ;;wCAAC;wCAAEH,WAAWI,WAAW;wCAAC;;;8CACxC,qBAACT,SAAI;8CAAE,AAAC,IAAa,OAAVO,KAAKI,IAAI;;;2BAFX,AAAC,GAA4BD,OAA1BL,WAAWI,WAAW,EAAC,KAAS,OAANC;;gBAK5C;;;;AAIR"}
@@ -36,7 +36,7 @@ var _default = /*#__PURE__*/ (0, _react.memo)(function ExpandedOutput(param) {
36
36
  /*#__PURE__*/ (0, _jsxruntime.jsxs)(_ink.Text, {
37
37
  children: [
38
38
  "│ ",
39
- line.text
39
+ line.text || ' '
40
40
  ]
41
41
  }, scrollOffset + i));
42
42
  }),
@@ -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 ? (\n <Text dimColor>\n │ [+{remaining} more, Tab/⇧Tab page, {isMac ? '⌥↑/↓' : 'g/G'} top/bottom, ↵ close]\n </Text>\n ) : (\n <Text dimColor>│ [↵ close]</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"}
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, ↵ close]\n </Text>\n ) : (\n <Text dimColor>│ [↵ close]</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,IAAI;;mBAAlChB,eAAee;;YAE3BV,wBACC,sBAACK,SAAI;gBAACC,QAAQ;;oBAAC;oBACRJ;oBAAU;oBAAuBb,QAAQ,SAAS;oBAAM;;+BAG/D,qBAACgB,SAAI;gBAACC,QAAQ;0BAAC;;;;AAIvB"}
@@ -69,7 +69,7 @@ var _default = /*#__PURE__*/ (0, _react.memo)(function FullscreenOverlay(param)
69
69
  }) : visibleLines.map(function(line, i) {
70
70
  return(// biome-ignore lint/suspicious/noArrayIndexKey: Lines have no unique ID, index is stable for this scrolling view
71
71
  /*#__PURE__*/ (0, _jsxruntime.jsx)(_ink.Text, {
72
- children: line.text
72
+ children: line.text || ' '
73
73
  }, scrollOffset + i));
74
74
  })
75
75
  }),
@@ -1 +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, useLayoutEffect, useRef } 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';\nconst HIDE_CURSOR = '\\x1b[?25l';\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 const enteredRef = useRef(false);\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 SYNCHRONOUSLY on first render, before ink outputs anything\n if (!enteredRef.current && stdout) {\n stdout.write(ENTER_ALT_SCREEN + CLEAR_SCREEN + CURSOR_HOME + HIDE_CURSOR);\n enteredRef.current = true;\n }\n\n // Exit alternate screen on unmount\n useLayoutEffect(() => {\n return () => {\n if (stdout && enteredRef.current) {\n stdout.write(EXIT_ALT_SCREEN);\n enteredRef.current = false;\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","HIDE_CURSOR","memo","FullscreenOverlay","title","lines","scrollOffset","stdout","useStdout","terminalHeight","rows","enteredRef","useRef","headerLines","footerLines","maxVisible","Math","max","current","write","useLayoutEffect","visibleLines","slice","totalLines","length","currentLine","endLine","min","Box","flexDirection","height","Text","bold","color","dimColor","repeat","columns","flexGrow","map","line","i","text"],"mappings":";;;;+BAoBA;;;eAAA;;;;mBApBqC;qBACS;AAG9C,IAAMA,QAAQC,QAAQC,QAAQ,KAAK;AAEnC,gDAAgD;AAChD,IAAMC,mBAAmB;AACzB,IAAMC,kBAAkB;AACxB,IAAMC,eAAe;AACrB,IAAMC,cAAc;AACpB,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;IACvC,IAAMC,aAAaC,IAAAA,aAAM,EAAC;IAE1B,sEAAsE;IACtE,IAAMC,cAAc;IACpB,IAAMC,cAAc;IACpB,IAAMC,aAAaC,KAAKC,GAAG,CAAC,GAAGR,iBAAiBI,cAAcC;IAE9D,oFAAoF;IACpF,IAAI,CAACH,WAAWO,OAAO,IAAIX,QAAQ;QACjCA,OAAOY,KAAK,CAACtB,mBAAmBE,eAAeC,cAAcC;QAC7DU,WAAWO,OAAO,GAAG;IACvB;IAEA,mCAAmC;IACnCE,IAAAA,sBAAe,EAAC;QACd,OAAO;YACL,IAAIb,UAAUI,WAAWO,OAAO,EAAE;gBAChCX,OAAOY,KAAK,CAACrB;gBACba,WAAWO,OAAO,GAAG;YACvB;QACF;IACF,GAAG;QAACX;KAAO;IAEX,IAAMc,eAAehB,MAAMiB,KAAK,CAAChB,cAAcA,eAAeS;IAC9D,IAAMQ,aAAalB,MAAMmB,MAAM;IAC/B,IAAMC,cAAcnB,eAAe;IACnC,IAAMoB,UAAUV,KAAKW,GAAG,CAACrB,eAAeS,YAAYQ;IAEpD,qBACE,sBAACK,QAAG;QAACC,eAAc;QAASC,QAAQrB;;0BAElC,qBAACsB,SAAI;gBAACC,IAAI;gBAACC,OAAM;0BACd7B;;0BAEH,qBAAC2B,SAAI;gBAACG,QAAQ;0BAAE,IAAIC,MAAM,CAACnB,KAAKW,GAAG,CAAC,IAAIpB,CAAAA,mBAAAA,6BAAAA,OAAQ6B,OAAO,KAAI;;0BAG3D,qBAACR,QAAG;gBAACC,eAAc;gBAASQ,UAAU;0BACnChC,MAAMmB,MAAM,KAAK,kBAChB,qBAACO,SAAI;oBAACG,QAAQ;8BAAC;qBAEfb,aAAaiB,GAAG,CAAC,SAACC,MAAMC;2BACtB,iHAAiH;kCACjH,qBAACT,SAAI;kCAAyBQ,KAAKE,IAAI;uBAA5BnC,eAAekC;;;0BAMhC,sBAACT,SAAI;gBAACG,QAAQ;;oBAAC;oBACNT;oBAAY;oBAAEC;oBAAQ;oBAAKH;oBAAW;oBAAiC7B,QAAQ,SAAS;oBAAM;;;;;AAI7G"}
1
+ {"version":3,"sources":["/Users/kevin/Dev/OpenSource/node/spawn-term/src/components/FullscreenOverlay.tsx"],"sourcesContent":["import { Box, Text, useStdout } from 'ink';\nimport { memo, useLayoutEffect, useRef } 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';\nconst HIDE_CURSOR = '\\x1b[?25l';\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 const enteredRef = useRef(false);\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 SYNCHRONOUSLY on first render, before ink outputs anything\n if (!enteredRef.current && stdout) {\n stdout.write(ENTER_ALT_SCREEN + CLEAR_SCREEN + CURSOR_HOME + HIDE_CURSOR);\n enteredRef.current = true;\n }\n\n // Exit alternate screen on unmount\n useLayoutEffect(() => {\n return () => {\n if (stdout && enteredRef.current) {\n stdout.write(EXIT_ALT_SCREEN);\n enteredRef.current = false;\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","HIDE_CURSOR","memo","FullscreenOverlay","title","lines","scrollOffset","stdout","useStdout","terminalHeight","rows","enteredRef","useRef","headerLines","footerLines","maxVisible","Math","max","current","write","useLayoutEffect","visibleLines","slice","totalLines","length","currentLine","endLine","min","Box","flexDirection","height","Text","bold","color","dimColor","repeat","columns","flexGrow","map","line","i","text"],"mappings":";;;;+BAoBA;;;eAAA;;;;mBApBqC;qBACS;AAG9C,IAAMA,QAAQC,QAAQC,QAAQ,KAAK;AAEnC,gDAAgD;AAChD,IAAMC,mBAAmB;AACzB,IAAMC,kBAAkB;AACxB,IAAMC,eAAe;AACrB,IAAMC,cAAc;AACpB,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;IACvC,IAAMC,aAAaC,IAAAA,aAAM,EAAC;IAE1B,sEAAsE;IACtE,IAAMC,cAAc;IACpB,IAAMC,cAAc;IACpB,IAAMC,aAAaC,KAAKC,GAAG,CAAC,GAAGR,iBAAiBI,cAAcC;IAE9D,oFAAoF;IACpF,IAAI,CAACH,WAAWO,OAAO,IAAIX,QAAQ;QACjCA,OAAOY,KAAK,CAACtB,mBAAmBE,eAAeC,cAAcC;QAC7DU,WAAWO,OAAO,GAAG;IACvB;IAEA,mCAAmC;IACnCE,IAAAA,sBAAe,EAAC;QACd,OAAO;YACL,IAAIb,UAAUI,WAAWO,OAAO,EAAE;gBAChCX,OAAOY,KAAK,CAACrB;gBACba,WAAWO,OAAO,GAAG;YACvB;QACF;IACF,GAAG;QAACX;KAAO;IAEX,IAAMc,eAAehB,MAAMiB,KAAK,CAAChB,cAAcA,eAAeS;IAC9D,IAAMQ,aAAalB,MAAMmB,MAAM;IAC/B,IAAMC,cAAcnB,eAAe;IACnC,IAAMoB,UAAUV,KAAKW,GAAG,CAACrB,eAAeS,YAAYQ;IAEpD,qBACE,sBAACK,QAAG;QAACC,eAAc;QAASC,QAAQrB;;0BAElC,qBAACsB,SAAI;gBAACC,IAAI;gBAACC,OAAM;0BACd7B;;0BAEH,qBAAC2B,SAAI;gBAACG,QAAQ;0BAAE,IAAIC,MAAM,CAACnB,KAAKW,GAAG,CAAC,IAAIpB,CAAAA,mBAAAA,6BAAAA,OAAQ6B,OAAO,KAAI;;0BAG3D,qBAACR,QAAG;gBAACC,eAAc;gBAASQ,UAAU;0BACnChC,MAAMmB,MAAM,KAAK,kBAChB,qBAACO,SAAI;oBAACG,QAAQ;8BAAC;qBAEfb,aAAaiB,GAAG,CAAC,SAACC,MAAMC;2BACtB,iHAAiH;kCACjH,qBAACT,SAAI;kCAAyBQ,KAAKE,IAAI,IAAI;uBAAhCnC,eAAekC;;;0BAMhC,sBAACT,SAAI;gBAACG,QAAQ;;oBAAC;oBACNT;oBAAY;oBAAEC;oBAAQ;oBAAKH;oBAAW;oBAAiC7B,QAAQ,SAAS;oBAAM;;;;;AAI7G"}
@@ -9,14 +9,6 @@ Object.defineProperty(exports, "TerminalBuffer", {
9
9
  }
10
10
  });
11
11
  var _terminalmodel = require("terminal-model");
12
- function _array_like_to_array(arr, len) {
13
- if (len == null || len > arr.length) len = arr.length;
14
- for(var i = 0, arr2 = new Array(len); i < len; i++)arr2[i] = arr[i];
15
- return arr2;
16
- }
17
- function _array_without_holes(arr) {
18
- if (Array.isArray(arr)) return _array_like_to_array(arr);
19
- }
20
12
  function _class_call_check(instance, Constructor) {
21
13
  if (!(instance instanceof Constructor)) {
22
14
  throw new TypeError("Cannot call a class as a function");
@@ -36,23 +28,6 @@ function _create_class(Constructor, protoProps, staticProps) {
36
28
  if (staticProps) _defineProperties(Constructor, staticProps);
37
29
  return Constructor;
38
30
  }
39
- function _iterable_to_array(iter) {
40
- if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter);
41
- }
42
- function _non_iterable_spread() {
43
- throw new TypeError("Invalid attempt to spread non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
44
- }
45
- function _to_consumable_array(arr) {
46
- return _array_without_holes(arr) || _iterable_to_array(arr) || _unsupported_iterable_to_array(arr) || _non_iterable_spread();
47
- }
48
- function _unsupported_iterable_to_array(o, minLen) {
49
- if (!o) return;
50
- if (typeof o === "string") return _array_like_to_array(o, minLen);
51
- var n = Object.prototype.toString.call(o).slice(8, -1);
52
- if (n === "Object" && o.constructor) n = o.constructor.name;
53
- if (n === "Map" || n === "Set") return Array.from(n);
54
- if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array(o, minLen);
55
- }
56
31
  var TerminalBuffer = /*#__PURE__*/ function() {
57
32
  "use strict";
58
33
  function TerminalBuffer(_cols) {
@@ -99,7 +74,7 @@ var TerminalBuffer = /*#__PURE__*/ function() {
99
74
  }
100
75
  // Return copy of all lines WITHOUT trimStart() or trimming blank lines
101
76
  // Preserves all whitespace, indentation, and blank lines
102
- return _to_consumable_array(this.allLines);
77
+ return this.allLines.slice();
103
78
  };
104
79
  /**
105
80
  * Clean up terminal resources.
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/OpenSource/node/spawn-term/src/lib/TerminalBuffer.ts"],"sourcesContent":["import { StreamingTerminal } from 'terminal-model';\n\n/**\n * Wrapper around terminal-model's StreamingTerminal 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 *\n * This implementation preserves whitespace and blank lines by NOT calling trimStart(),\n * which was the bug in the previous xterm-based implementation.\n */\nexport class TerminalBuffer {\n private terminal: StreamingTerminal;\n private allLines: string[] = [];\n\n constructor(_cols: number, _scrollback = 10000) {\n // terminal-model doesn't enforce column width during parsing\n // It preserves all content as-is\n this.terminal = new StreamingTerminal();\n\n // Listen for completed lines (when \\n is encountered)\n this.terminal.setLineReadyCallback(() => {\n const line = this.terminal.renderLine();\n this.terminal.reset();\n this.allLines.push(line);\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 this.terminal.write(data);\n }\n\n /**\n * Resize the terminal width.\n * terminal-model doesn't use column constraints, so this is a no-op for compatibility.\n */\n resize(_cols: number): void {\n // No-op - terminal-model doesn't enforce column width\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, with color codes preserved.\n *\n * CRITICAL: Unlike the xterm implementation, we do NOT call trimStart(),\n * which preserves legitimate indentation and blank lines.\n */\n getLines(): string[] {\n // Flush any pending content (incomplete line without \\n)\n if (this.terminal.hasContent()) {\n const line = this.terminal.renderLine();\n this.terminal.reset();\n this.allLines.push(line);\n }\n\n // Return copy of all lines WITHOUT trimStart() or trimming blank lines\n // Preserves all whitespace, indentation, and blank lines\n return [...this.allLines];\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 this.allLines = [];\n }\n}\n"],"names":["TerminalBuffer","_cols","_scrollback","allLines","terminal","StreamingTerminal","setLineReadyCallback","line","renderLine","reset","push","write","data","resize","getLines","hasContent","dispose","lineCount","length"],"mappings":";;;;+BAUaA;;;eAAAA;;;6BAVqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAU3B,IAAA,AAAMA,+BAAN;;aAAMA,eAICC,KAAa;;YAAEC,cAAAA,iEAAc;gCAJ9BF;aAEHG,WAAqB,EAAE;QAG7B,6DAA6D;QAC7D,iCAAiC;QACjC,IAAI,CAACC,QAAQ,GAAG,IAAIC,gCAAiB;QAErC,sDAAsD;QACtD,IAAI,CAACD,QAAQ,CAACE,oBAAoB,CAAC;YACjC,IAAMC,OAAO,MAAKH,QAAQ,CAACI,UAAU;YACrC,MAAKJ,QAAQ,CAACK,KAAK;YACnB,MAAKN,QAAQ,CAACO,IAAI,CAACH;QACrB;;iBAdSP;IAiBX;;;GAGC,GACDW,OAAAA,KAEC,GAFDA,SAAAA,MAAMC,IAAqB;QACzB,IAAI,CAACR,QAAQ,CAACO,KAAK,CAACC;IACtB;IAEA;;;GAGC,GACDC,OAAAA,MAEC,GAFDA,SAAAA,OAAOZ,KAAa;IAClB,sDAAsD;IACxD;IAEA;;;;;;;GAOC,GACDa,OAAAA,QAWC,GAXDA,SAAAA;QACE,yDAAyD;QACzD,IAAI,IAAI,CAACV,QAAQ,CAACW,UAAU,IAAI;YAC9B,IAAMR,OAAO,IAAI,CAACH,QAAQ,CAACI,UAAU;YACrC,IAAI,CAACJ,QAAQ,CAACK,KAAK;YACnB,IAAI,CAACN,QAAQ,CAACO,IAAI,CAACH;QACrB;QAEA,uEAAuE;QACvE,yDAAyD;QACzD,OAAQ,qBAAG,IAAI,CAACJ,QAAQ;IAC1B;IASA;;GAEC,GACDa,OAAAA,OAGC,GAHDA,SAAAA;QACE,IAAI,CAACZ,QAAQ,CAACY,OAAO;QACrB,IAAI,CAACb,QAAQ,GAAG,EAAE;IACpB;kBAnEWH;;YAyDPiB,KAAAA;iBAAJ,AAHA;;GAEC,GACD;gBACE,OAAO,IAAI,CAACH,QAAQ,GAAGI,MAAM;YAC/B;;;WA3DWlB"}
1
+ {"version":3,"sources":["/Users/kevin/Dev/OpenSource/node/spawn-term/src/lib/TerminalBuffer.ts"],"sourcesContent":["import { StreamingTerminal } from 'terminal-model';\n\n/**\n * Wrapper around terminal-model's StreamingTerminal 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 *\n * This implementation preserves whitespace and blank lines by NOT calling trimStart(),\n * which was the bug in the previous xterm-based implementation.\n */\nexport class TerminalBuffer {\n private terminal: StreamingTerminal;\n private allLines: string[] = [];\n\n constructor(_cols: number, _scrollback = 10000) {\n // terminal-model doesn't enforce column width during parsing\n // It preserves all content as-is\n this.terminal = new StreamingTerminal();\n\n // Listen for completed lines (when \\n is encountered)\n this.terminal.setLineReadyCallback(() => {\n const line = this.terminal.renderLine();\n this.terminal.reset();\n this.allLines.push(line);\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 this.terminal.write(data);\n }\n\n /**\n * Resize the terminal width.\n * terminal-model doesn't use column constraints, so this is a no-op for compatibility.\n */\n resize(_cols: number): void {\n // No-op - terminal-model doesn't enforce column width\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, with color codes preserved.\n *\n * CRITICAL: Unlike the xterm implementation, we do NOT call trimStart(),\n * which preserves legitimate indentation and blank lines.\n */\n getLines(): string[] {\n // Flush any pending content (incomplete line without \\n)\n if (this.terminal.hasContent()) {\n const line = this.terminal.renderLine();\n this.terminal.reset();\n this.allLines.push(line);\n }\n\n // Return copy of all lines WITHOUT trimStart() or trimming blank lines\n // Preserves all whitespace, indentation, and blank lines\n return this.allLines.slice();\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 this.allLines = [];\n }\n}\n"],"names":["TerminalBuffer","_cols","_scrollback","allLines","terminal","StreamingTerminal","setLineReadyCallback","line","renderLine","reset","push","write","data","resize","getLines","hasContent","slice","dispose","lineCount","length"],"mappings":";;;;+BAUaA;;;eAAAA;;;6BAVqB;;;;;;;;;;;;;;;;;;;;AAU3B,IAAA,AAAMA,+BAAN;;aAAMA,eAICC,KAAa;;YAAEC,cAAAA,iEAAc;gCAJ9BF;aAEHG,WAAqB,EAAE;QAG7B,6DAA6D;QAC7D,iCAAiC;QACjC,IAAI,CAACC,QAAQ,GAAG,IAAIC,gCAAiB;QAErC,sDAAsD;QACtD,IAAI,CAACD,QAAQ,CAACE,oBAAoB,CAAC;YACjC,IAAMC,OAAO,MAAKH,QAAQ,CAACI,UAAU;YACrC,MAAKJ,QAAQ,CAACK,KAAK;YACnB,MAAKN,QAAQ,CAACO,IAAI,CAACH;QACrB;;iBAdSP;IAiBX;;;GAGC,GACDW,OAAAA,KAEC,GAFDA,SAAAA,MAAMC,IAAqB;QACzB,IAAI,CAACR,QAAQ,CAACO,KAAK,CAACC;IACtB;IAEA;;;GAGC,GACDC,OAAAA,MAEC,GAFDA,SAAAA,OAAOZ,KAAa;IAClB,sDAAsD;IACxD;IAEA;;;;;;;GAOC,GACDa,OAAAA,QAWC,GAXDA,SAAAA;QACE,yDAAyD;QACzD,IAAI,IAAI,CAACV,QAAQ,CAACW,UAAU,IAAI;YAC9B,IAAMR,OAAO,IAAI,CAACH,QAAQ,CAACI,UAAU;YACrC,IAAI,CAACJ,QAAQ,CAACK,KAAK;YACnB,IAAI,CAACN,QAAQ,CAACO,IAAI,CAACH;QACrB;QAEA,uEAAuE;QACvE,yDAAyD;QACzD,OAAO,IAAI,CAACJ,QAAQ,CAACa,KAAK;IAC5B;IASA;;GAEC,GACDC,OAAAA,OAGC,GAHDA,SAAAA;QACE,IAAI,CAACb,QAAQ,CAACa,OAAO;QACrB,IAAI,CAACd,QAAQ,GAAG,EAAE;IACpB;kBAnEWH;;YAyDPkB,KAAAA;iBAAJ,AAHA;;GAEC,GACD;gBACE,OAAO,IAAI,CAACJ,QAAQ,GAAGK,MAAM;YAC/B;;;WA3DWnB"}
@@ -41,7 +41,7 @@ const RunningSummary = /*#__PURE__*/ memo(function RunningSummary({ line }) {
41
41
  return /*#__PURE__*/ _jsx(Box, {
42
42
  marginLeft: 2,
43
43
  children: /*#__PURE__*/ _jsx(Text, {
44
- children: line.text
44
+ children: line.text || ' '
45
45
  })
46
46
  });
47
47
  });
@@ -49,7 +49,7 @@ const renderLine = (line, index)=>{
49
49
  return /*#__PURE__*/ _jsx(Box, {
50
50
  minHeight: 1,
51
51
  children: /*#__PURE__*/ _jsx(Text, {
52
- children: line.text
52
+ children: line.text || ' '
53
53
  })
54
54
  }, index);
55
55
  };
@@ -82,9 +82,8 @@ const Contracted = /*#__PURE__*/ memo(function Contracted({ item }) {
82
82
  const errors = useMemo(()=>lines.filter((line)=>line.type === LineType.stderr), [
83
83
  lines
84
84
  ]);
85
- const summary = useMemo(()=>lines.filter((line)=>line.text.length > 0 && errors.indexOf(line) < 0).pop(), [
86
- lines,
87
- errors
85
+ const summary = useMemo(()=>lines.filter((line)=>line.type !== LineType.stderr && line.text.length > 0).pop(), [
86
+ lines
88
87
  ]);
89
88
  return /*#__PURE__*/ _jsxs(Box, {
90
89
  flexDirection: "column",
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/OpenSource/node/spawn-term/src/components/ChildProcess.tsx"],"sourcesContent":["import { Box, Text } from 'ink';\nimport { memo, useMemo } from 'react';\nimport { SPINNER } from '../constants.ts';\nimport figures from '../lib/figures.ts';\nimport type { ChildProcess as ChildProcessT, Line, State } from '../types.ts';\nimport { LineType } from '../types.ts';\nimport Spinner from './Spinner.ts';\n\nconst BLANK_LINE = { type: LineType.stdout, text: '' };\n\nconst ICONS = {\n error: <Text color=\"red\">{figures.cross}</Text>,\n success: <Text color=\"green\">{figures.tick}</Text>,\n running: <Spinner {...SPINNER} />,\n};\n\ntype ItemProps = {\n item: ChildProcessT;\n};\n\ntype HeaderProps = {\n group?: string;\n title: string;\n state: State;\n};\n\nconst Header = memo(\n function Header({ group, title, state }: HeaderProps) {\n const icon = ICONS[state];\n\n return (\n <Box>\n {icon}\n {group && <Text bold>{`${group}${figures.pointer} `}</Text>}\n <Text>{title}</Text>\n </Box>\n );\n },\n (a, b) => a.group === b.group && a.title === b.title && a.state === b.state\n);\n\ntype RunningSummaryProps = {\n line: Line;\n};\n\nconst RunningSummary = memo(function RunningSummary({ line }: RunningSummaryProps) {\n return (\n <Box marginLeft={2}>\n <Text>{line.text}</Text>\n </Box>\n );\n});\n\ntype LinesProps = {\n lines: Line[];\n};\n\nconst renderLine = (line, index) => {\n return (\n <Box key={index} minHeight={1}>\n <Text>{line.text}</Text>\n </Box>\n );\n};\n\nconst Lines = memo(function Lines({ lines }: LinesProps) {\n return (\n <Box flexDirection=\"column\" marginLeft={2}>\n {lines.map(renderLine)}\n </Box>\n );\n});\n\nconst Expanded = memo(function Expanded({ item }: ItemProps) {\n const { lines } = item;\n\n return (\n <Box flexDirection=\"column\">\n <Header group={item.group} title={item.title} state={item.state} />\n <Lines lines={lines} />\n </Box>\n );\n});\n\nconst Contracted = memo(function Contracted({ item }: ItemProps) {\n const { state, lines } = item;\n\n // remove ansi codes when displaying single lines\n const errors = useMemo(() => lines.filter((line) => line.type === LineType.stderr), [lines]);\n const summary = useMemo(() => lines.filter((line) => line.text.length > 0 && errors.indexOf(line) < 0).pop(), [lines, errors]);\n\n return (\n <Box flexDirection=\"column\">\n <Header group={item.group} title={item.title} state={item.state} />\n {state === 'running' && <RunningSummary line={summary || BLANK_LINE} />}\n {errors.length > 0 && <Lines lines={errors} />}\n </Box>\n );\n});\n\nexport default memo(function ChildProcess({ item }: ItemProps) {\n const { expanded } = item;\n return expanded ? <Expanded item={item} /> : <Contracted item={item} />;\n});\n"],"names":["Box","Text","memo","useMemo","SPINNER","figures","LineType","Spinner","BLANK_LINE","type","stdout","text","ICONS","error","color","cross","success","tick","running","Header","group","title","state","icon","bold","pointer","a","b","RunningSummary","line","marginLeft","renderLine","index","minHeight","Lines","lines","flexDirection","map","Expanded","item","Contracted","errors","filter","stderr","summary","length","indexOf","pop","ChildProcess","expanded"],"mappings":"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"}
1
+ {"version":3,"sources":["/Users/kevin/Dev/OpenSource/node/spawn-term/src/components/ChildProcess.tsx"],"sourcesContent":["import { Box, Text } from 'ink';\nimport { memo, useMemo } from 'react';\nimport { SPINNER } from '../constants.ts';\nimport figures from '../lib/figures.ts';\nimport type { ChildProcess as ChildProcessT, Line, State } from '../types.ts';\nimport { LineType } from '../types.ts';\nimport Spinner from './Spinner.ts';\n\nconst BLANK_LINE = { type: LineType.stdout, text: '' };\n\nconst ICONS = {\n error: <Text color=\"red\">{figures.cross}</Text>,\n success: <Text color=\"green\">{figures.tick}</Text>,\n running: <Spinner {...SPINNER} />,\n};\n\ntype ItemProps = {\n item: ChildProcessT;\n};\n\ntype HeaderProps = {\n group?: string;\n title: string;\n state: State;\n};\n\nconst Header = memo(\n function Header({ group, title, state }: HeaderProps) {\n const icon = ICONS[state];\n\n return (\n <Box>\n {icon}\n {group && <Text bold>{`${group}${figures.pointer} `}</Text>}\n <Text>{title}</Text>\n </Box>\n );\n },\n (a, b) => a.group === b.group && a.title === b.title && a.state === b.state\n);\n\ntype RunningSummaryProps = {\n line: Line;\n};\n\nconst RunningSummary = memo(function RunningSummary({ line }: RunningSummaryProps) {\n return (\n <Box marginLeft={2}>\n <Text>{line.text || ' '}</Text>\n </Box>\n );\n});\n\ntype LinesProps = {\n lines: Line[];\n};\n\nconst renderLine = (line, index) => {\n return (\n <Box key={index} minHeight={1}>\n <Text>{line.text || ' '}</Text>\n </Box>\n );\n};\n\nconst Lines = memo(function Lines({ lines }: LinesProps) {\n return (\n <Box flexDirection=\"column\" marginLeft={2}>\n {lines.map(renderLine)}\n </Box>\n );\n});\n\nconst Expanded = memo(function Expanded({ item }: ItemProps) {\n const { lines } = item;\n\n return (\n <Box flexDirection=\"column\">\n <Header group={item.group} title={item.title} state={item.state} />\n <Lines lines={lines} />\n </Box>\n );\n});\n\nconst Contracted = memo(function Contracted({ item }: ItemProps) {\n const { state, lines } = item;\n\n // remove ansi codes when displaying single lines\n const errors = useMemo(() => lines.filter((line) => line.type === LineType.stderr), [lines]);\n const summary = useMemo(() => lines.filter((line) => line.type !== LineType.stderr && line.text.length > 0).pop(), [lines]);\n\n return (\n <Box flexDirection=\"column\">\n <Header group={item.group} title={item.title} state={item.state} />\n {state === 'running' && <RunningSummary line={summary || BLANK_LINE} />}\n {errors.length > 0 && <Lines lines={errors} />}\n </Box>\n );\n});\n\nexport default memo(function ChildProcess({ item }: ItemProps) {\n const { expanded } = item;\n return expanded ? <Expanded item={item} /> : <Contracted item={item} />;\n});\n"],"names":["Box","Text","memo","useMemo","SPINNER","figures","LineType","Spinner","BLANK_LINE","type","stdout","text","ICONS","error","color","cross","success","tick","running","Header","group","title","state","icon","bold","pointer","a","b","RunningSummary","line","marginLeft","renderLine","index","minHeight","Lines","lines","flexDirection","map","Expanded","item","Contracted","errors","filter","stderr","summary","length","pop","ChildProcess","expanded"],"mappings":"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"}
@@ -76,8 +76,9 @@ export default /*#__PURE__*/ memo(function ErrorFooter({ errors, isExpanded }) {
76
76
  "]"
77
77
  ]
78
78
  }),
79
- " ",
80
- line.text
79
+ /*#__PURE__*/ _jsx(Text, {
80
+ children: ` ${line.text}`
81
+ })
81
82
  ]
82
83
  }, `${errorGroup.processName}-${index}`));
83
84
  })
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/OpenSource/node/spawn-term/src/components/ErrorFooter.tsx"],"sourcesContent":["import { Box, Text } from 'ink';\nimport { memo } from 'react';\nimport type { Line } from '../types.ts';\nimport { LineType } from '../types.ts';\nimport Divider from './Divider.ts';\n\ntype ErrorGroup = {\n processName: string;\n lines: Line[];\n};\n\ntype Props = {\n errors: ErrorGroup[];\n isExpanded: boolean;\n};\n\nexport default memo(function ErrorFooter({ errors, isExpanded }: Props) {\n // Calculate totals for collapsed summary\n const totalLines = errors.reduce((sum, e) => sum + e.lines.filter((l) => l.type === LineType.stderr).length, 0);\n const totalProcesses = errors.length;\n\n if (totalProcesses === 0) {\n return null;\n }\n\n const processText = totalProcesses === 1 ? 'process' : 'processes';\n\n if (!isExpanded) {\n // Collapsed view - single summary line\n const summary = totalLines > 0 ? `${totalLines} error line${totalLines === 1 ? '' : 's'} in ${totalProcesses} ${processText}` : `${totalProcesses} failed ${processText}`;\n return (\n <>\n <Divider />\n <Text>\n <Text color=\"red\">{'\\u25b8'}</Text>\n {` ${summary}`}\n </Text>\n </>\n );\n }\n\n // Expanded view - show all error lines (or just process names if no stderr)\n return (\n <>\n <Divider />\n <Text>\n <Text color=\"red\">{'\\u25be'}</Text>\n {' Errors'}\n </Text>\n <Box flexDirection=\"column\">\n {errors.map((errorGroup) => {\n const stderrLines = errorGroup.lines.filter((line) => line.type === LineType.stderr);\n if (stderrLines.length === 0) {\n // No stderr output - just show process name\n return (\n <Text key={errorGroup.processName}>\n <Text dimColor>[{errorGroup.processName}]</Text> <Text color=\"red\">(failed)</Text>\n </Text>\n );\n }\n return stderrLines.map((line, index) => (\n <Text key={`${errorGroup.processName}-${index}`}>\n <Text dimColor>[{errorGroup.processName}]</Text> {line.text}\n </Text>\n ));\n })}\n </Box>\n </>\n );\n});\n"],"names":["Box","Text","memo","LineType","Divider","ErrorFooter","errors","isExpanded","totalLines","reduce","sum","e","lines","filter","l","type","stderr","length","totalProcesses","processText","summary","color","flexDirection","map","errorGroup","stderrLines","line","dimColor","processName","index","text"],"mappings":";AAAA,SAASA,GAAG,EAAEC,IAAI,QAAQ,MAAM;AAChC,SAASC,IAAI,QAAQ,QAAQ;AAE7B,SAASC,QAAQ,QAAQ,cAAc;AACvC,OAAOC,aAAa,eAAe;AAYnC,6BAAeF,KAAK,SAASG,YAAY,EAAEC,MAAM,EAAEC,UAAU,EAAS;IACpE,yCAAyC;IACzC,MAAMC,aAAaF,OAAOG,MAAM,CAAC,CAACC,KAAKC,IAAMD,MAAMC,EAAEC,KAAK,CAACC,MAAM,CAAC,CAACC,IAAMA,EAAEC,IAAI,KAAKZ,SAASa,MAAM,EAAEC,MAAM,EAAE;IAC7G,MAAMC,iBAAiBZ,OAAOW,MAAM;IAEpC,IAAIC,mBAAmB,GAAG;QACxB,OAAO;IACT;IAEA,MAAMC,cAAcD,mBAAmB,IAAI,YAAY;IAEvD,IAAI,CAACX,YAAY;QACf,uCAAuC;QACvC,MAAMa,UAAUZ,aAAa,IAAI,GAAGA,WAAW,WAAW,EAAEA,eAAe,IAAI,KAAK,IAAI,IAAI,EAAEU,eAAe,CAAC,EAAEC,aAAa,GAAG,GAAGD,eAAe,QAAQ,EAAEC,aAAa;QACzK,qBACE;;8BACE,KAACf;8BACD,MAACH;;sCACC,KAACA;4BAAKoB,OAAM;sCAAO;;wBAClB,CAAC,CAAC,EAAED,SAAS;;;;;IAItB;IAEA,4EAA4E;IAC5E,qBACE;;0BACE,KAAChB;0BACD,MAACH;;kCACC,KAACA;wBAAKoB,OAAM;kCAAO;;oBAClB;;;0BAEH,KAACrB;gBAAIsB,eAAc;0BAChBhB,OAAOiB,GAAG,CAAC,CAACC;oBACX,MAAMC,cAAcD,WAAWZ,KAAK,CAACC,MAAM,CAAC,CAACa,OAASA,KAAKX,IAAI,KAAKZ,SAASa,MAAM;oBACnF,IAAIS,YAAYR,MAAM,KAAK,GAAG;wBAC5B,4CAA4C;wBAC5C,qBACE,MAAChB;;8CACC,MAACA;oCAAK0B,QAAQ;;wCAAC;wCAAEH,WAAWI,WAAW;wCAAC;;;gCAAQ;8CAAC,KAAC3B;oCAAKoB,OAAM;8CAAM;;;2BAD1DG,WAAWI,WAAW;oBAIrC;oBACA,OAAOH,YAAYF,GAAG,CAAC,CAACG,MAAMG,sBAC5B,MAAC5B;;8CACC,MAACA;oCAAK0B,QAAQ;;wCAAC;wCAAEH,WAAWI,WAAW;wCAAC;;;gCAAQ;gCAAEF,KAAKI,IAAI;;2BADlD,GAAGN,WAAWI,WAAW,CAAC,CAAC,EAAEC,OAAO;gBAInD;;;;AAIR,GAAG"}
1
+ {"version":3,"sources":["/Users/kevin/Dev/OpenSource/node/spawn-term/src/components/ErrorFooter.tsx"],"sourcesContent":["import { Box, Text } from 'ink';\nimport { memo } from 'react';\nimport type { Line } from '../types.ts';\nimport { LineType } from '../types.ts';\nimport Divider from './Divider.ts';\n\ntype ErrorGroup = {\n processName: string;\n lines: Line[];\n};\n\ntype Props = {\n errors: ErrorGroup[];\n isExpanded: boolean;\n};\n\nexport default memo(function ErrorFooter({ errors, isExpanded }: Props) {\n // Calculate totals for collapsed summary\n const totalLines = errors.reduce((sum, e) => sum + e.lines.filter((l) => l.type === LineType.stderr).length, 0);\n const totalProcesses = errors.length;\n\n if (totalProcesses === 0) {\n return null;\n }\n\n const processText = totalProcesses === 1 ? 'process' : 'processes';\n\n if (!isExpanded) {\n // Collapsed view - single summary line\n const summary = totalLines > 0 ? `${totalLines} error line${totalLines === 1 ? '' : 's'} in ${totalProcesses} ${processText}` : `${totalProcesses} failed ${processText}`;\n return (\n <>\n <Divider />\n <Text>\n <Text color=\"red\">{'\\u25b8'}</Text>\n {` ${summary}`}\n </Text>\n </>\n );\n }\n\n // Expanded view - show all error lines (or just process names if no stderr)\n return (\n <>\n <Divider />\n <Text>\n <Text color=\"red\">{'\\u25be'}</Text>\n {' Errors'}\n </Text>\n <Box flexDirection=\"column\">\n {errors.map((errorGroup) => {\n const stderrLines = errorGroup.lines.filter((line) => line.type === LineType.stderr);\n if (stderrLines.length === 0) {\n // No stderr output - just show process name\n return (\n <Text key={errorGroup.processName}>\n <Text dimColor>[{errorGroup.processName}]</Text> <Text color=\"red\">(failed)</Text>\n </Text>\n );\n }\n return stderrLines.map((line, index) => (\n <Text key={`${errorGroup.processName}-${index}`}>\n <Text dimColor>[{errorGroup.processName}]</Text>\n <Text>{` ${line.text}`}</Text>\n </Text>\n ));\n })}\n </Box>\n </>\n );\n});\n"],"names":["Box","Text","memo","LineType","Divider","ErrorFooter","errors","isExpanded","totalLines","reduce","sum","e","lines","filter","l","type","stderr","length","totalProcesses","processText","summary","color","flexDirection","map","errorGroup","stderrLines","line","dimColor","processName","index","text"],"mappings":";AAAA,SAASA,GAAG,EAAEC,IAAI,QAAQ,MAAM;AAChC,SAASC,IAAI,QAAQ,QAAQ;AAE7B,SAASC,QAAQ,QAAQ,cAAc;AACvC,OAAOC,aAAa,eAAe;AAYnC,6BAAeF,KAAK,SAASG,YAAY,EAAEC,MAAM,EAAEC,UAAU,EAAS;IACpE,yCAAyC;IACzC,MAAMC,aAAaF,OAAOG,MAAM,CAAC,CAACC,KAAKC,IAAMD,MAAMC,EAAEC,KAAK,CAACC,MAAM,CAAC,CAACC,IAAMA,EAAEC,IAAI,KAAKZ,SAASa,MAAM,EAAEC,MAAM,EAAE;IAC7G,MAAMC,iBAAiBZ,OAAOW,MAAM;IAEpC,IAAIC,mBAAmB,GAAG;QACxB,OAAO;IACT;IAEA,MAAMC,cAAcD,mBAAmB,IAAI,YAAY;IAEvD,IAAI,CAACX,YAAY;QACf,uCAAuC;QACvC,MAAMa,UAAUZ,aAAa,IAAI,GAAGA,WAAW,WAAW,EAAEA,eAAe,IAAI,KAAK,IAAI,IAAI,EAAEU,eAAe,CAAC,EAAEC,aAAa,GAAG,GAAGD,eAAe,QAAQ,EAAEC,aAAa;QACzK,qBACE;;8BACE,KAACf;8BACD,MAACH;;sCACC,KAACA;4BAAKoB,OAAM;sCAAO;;wBAClB,CAAC,CAAC,EAAED,SAAS;;;;;IAItB;IAEA,4EAA4E;IAC5E,qBACE;;0BACE,KAAChB;0BACD,MAACH;;kCACC,KAACA;wBAAKoB,OAAM;kCAAO;;oBAClB;;;0BAEH,KAACrB;gBAAIsB,eAAc;0BAChBhB,OAAOiB,GAAG,CAAC,CAACC;oBACX,MAAMC,cAAcD,WAAWZ,KAAK,CAACC,MAAM,CAAC,CAACa,OAASA,KAAKX,IAAI,KAAKZ,SAASa,MAAM;oBACnF,IAAIS,YAAYR,MAAM,KAAK,GAAG;wBAC5B,4CAA4C;wBAC5C,qBACE,MAAChB;;8CACC,MAACA;oCAAK0B,QAAQ;;wCAAC;wCAAEH,WAAWI,WAAW;wCAAC;;;gCAAQ;8CAAC,KAAC3B;oCAAKoB,OAAM;8CAAM;;;2BAD1DG,WAAWI,WAAW;oBAIrC;oBACA,OAAOH,YAAYF,GAAG,CAAC,CAACG,MAAMG,sBAC5B,MAAC5B;;8CACC,MAACA;oCAAK0B,QAAQ;;wCAAC;wCAAEH,WAAWI,WAAW;wCAAC;;;8CACxC,KAAC3B;8CAAM,CAAC,CAAC,EAAEyB,KAAKI,IAAI,EAAE;;;2BAFb,GAAGN,WAAWI,WAAW,CAAC,CAAC,EAAEC,OAAO;gBAKnD;;;;AAIR,GAAG"}
@@ -24,7 +24,7 @@ export default /*#__PURE__*/ memo(function ExpandedOutput({ lines, scrollOffset,
24
24
  /*#__PURE__*/ _jsxs(Text, {
25
25
  children: [
26
26
  "│ ",
27
- line.text
27
+ line.text || ' '
28
28
  ]
29
29
  }, scrollOffset + i)),
30
30
  hasMore ? /*#__PURE__*/ _jsxs(Text, {
@@ -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 ? (\n <Text dimColor>\n │ [+{remaining} more, Tab/⇧Tab page, {isMac ? '⌥↑/↓' : 'g/G'} top/bottom, ↵ close]\n </Text>\n ) : (\n <Text dimColor>│ [↵ close]</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"}
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, ↵ close]\n </Text>\n ) : (\n <Text dimColor>│ [↵ close]</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,IAAI;;mBAAlCb,eAAeY;YAE3BR,wBACC,MAACZ;gBAAKgB,QAAQ;;oBAAC;oBACRF;oBAAU;oBAAuBX,QAAQ,SAAS;oBAAM;;+BAG/D,KAACH;gBAAKgB,QAAQ;0BAAC;;;;AAIvB,GAAG"}
@@ -57,7 +57,7 @@ export default /*#__PURE__*/ memo(function FullscreenOverlay({ title, lines, scr
57
57
  children: "(no output)"
58
58
  }) : visibleLines.map((line, i)=>// biome-ignore lint/suspicious/noArrayIndexKey: Lines have no unique ID, index is stable for this scrolling view
59
59
  /*#__PURE__*/ _jsx(Text, {
60
- children: line.text
60
+ children: line.text || ' '
61
61
  }, scrollOffset + i))
62
62
  }),
63
63
  /*#__PURE__*/ _jsxs(Text, {
@@ -1 +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, useLayoutEffect, useRef } 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';\nconst HIDE_CURSOR = '\\x1b[?25l';\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 const enteredRef = useRef(false);\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 SYNCHRONOUSLY on first render, before ink outputs anything\n if (!enteredRef.current && stdout) {\n stdout.write(ENTER_ALT_SCREEN + CLEAR_SCREEN + CURSOR_HOME + HIDE_CURSOR);\n enteredRef.current = true;\n }\n\n // Exit alternate screen on unmount\n useLayoutEffect(() => {\n return () => {\n if (stdout && enteredRef.current) {\n stdout.write(EXIT_ALT_SCREEN);\n enteredRef.current = false;\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","useLayoutEffect","useRef","isMac","process","platform","ENTER_ALT_SCREEN","EXIT_ALT_SCREEN","CLEAR_SCREEN","CURSOR_HOME","HIDE_CURSOR","FullscreenOverlay","title","lines","scrollOffset","stdout","terminalHeight","rows","enteredRef","headerLines","footerLines","maxVisible","Math","max","current","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,eAAe,EAAEC,MAAM,QAAQ,QAAQ;AAGtD,MAAMC,QAAQC,QAAQC,QAAQ,KAAK;AAEnC,gDAAgD;AAChD,MAAMC,mBAAmB;AACzB,MAAMC,kBAAkB;AACxB,MAAMC,eAAe;AACrB,MAAMC,cAAc;AACpB,MAAMC,cAAc;AASpB,6BAAeV,KAAK,SAASW,kBAAkB,EAAEC,KAAK,EAAEC,KAAK,EAAEC,YAAY,EAAS;IAClF,MAAM,EAAEC,MAAM,EAAE,GAAGhB;IACnB,MAAMiB,iBAAiBD,CAAAA,mBAAAA,6BAAAA,OAAQE,IAAI,KAAI;IACvC,MAAMC,aAAahB,OAAO;IAE1B,sEAAsE;IACtE,MAAMiB,cAAc;IACpB,MAAMC,cAAc;IACpB,MAAMC,aAAaC,KAAKC,GAAG,CAAC,GAAGP,iBAAiBG,cAAcC;IAE9D,oFAAoF;IACpF,IAAI,CAACF,WAAWM,OAAO,IAAIT,QAAQ;QACjCA,OAAOU,KAAK,CAACnB,mBAAmBE,eAAeC,cAAcC;QAC7DQ,WAAWM,OAAO,GAAG;IACvB;IAEA,mCAAmC;IACnCvB,gBAAgB;QACd,OAAO;YACL,IAAIc,UAAUG,WAAWM,OAAO,EAAE;gBAChCT,OAAOU,KAAK,CAAClB;gBACbW,WAAWM,OAAO,GAAG;YACvB;QACF;IACF,GAAG;QAACT;KAAO;IAEX,MAAMW,eAAeb,MAAMc,KAAK,CAACb,cAAcA,eAAeO;IAC9D,MAAMO,aAAaf,MAAMgB,MAAM;IAC/B,MAAMC,cAAchB,eAAe;IACnC,MAAMiB,UAAUT,KAAKU,GAAG,CAAClB,eAAeO,YAAYO;IAEpD,qBACE,MAAC/B;QAAIoC,eAAc;QAASC,QAAQlB;;0BAElC,KAAClB;gBAAKqC,IAAI;gBAACC,OAAM;0BACdxB;;0BAEH,KAACd;gBAAKuC,QAAQ;0BAAE,IAAIC,MAAM,CAAChB,KAAKU,GAAG,CAAC,IAAIjB,CAAAA,mBAAAA,6BAAAA,OAAQwB,OAAO,KAAI;;0BAG3D,KAAC1C;gBAAIoC,eAAc;gBAASO,UAAU;0BACnC3B,MAAMgB,MAAM,KAAK,kBAChB,KAAC/B;oBAAKuC,QAAQ;8BAAC;qBAEfX,aAAae,GAAG,CAAC,CAACC,MAAMC,IACtB,iHAAiH;kCACjH,KAAC7C;kCAA6B4C,KAAKE,IAAI;uBAA5B9B,eAAe6B;;0BAMhC,MAAC7C;gBAAKuC,QAAQ;;oBAAC;oBACNP;oBAAY;oBAAEC;oBAAQ;oBAAKH;oBAAW;oBAAiCzB,QAAQ,SAAS;oBAAM;;;;;AAI7G,GAAG"}
1
+ {"version":3,"sources":["/Users/kevin/Dev/OpenSource/node/spawn-term/src/components/FullscreenOverlay.tsx"],"sourcesContent":["import { Box, Text, useStdout } from 'ink';\nimport { memo, useLayoutEffect, useRef } 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';\nconst HIDE_CURSOR = '\\x1b[?25l';\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 const enteredRef = useRef(false);\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 SYNCHRONOUSLY on first render, before ink outputs anything\n if (!enteredRef.current && stdout) {\n stdout.write(ENTER_ALT_SCREEN + CLEAR_SCREEN + CURSOR_HOME + HIDE_CURSOR);\n enteredRef.current = true;\n }\n\n // Exit alternate screen on unmount\n useLayoutEffect(() => {\n return () => {\n if (stdout && enteredRef.current) {\n stdout.write(EXIT_ALT_SCREEN);\n enteredRef.current = false;\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","useLayoutEffect","useRef","isMac","process","platform","ENTER_ALT_SCREEN","EXIT_ALT_SCREEN","CLEAR_SCREEN","CURSOR_HOME","HIDE_CURSOR","FullscreenOverlay","title","lines","scrollOffset","stdout","terminalHeight","rows","enteredRef","headerLines","footerLines","maxVisible","Math","max","current","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,eAAe,EAAEC,MAAM,QAAQ,QAAQ;AAGtD,MAAMC,QAAQC,QAAQC,QAAQ,KAAK;AAEnC,gDAAgD;AAChD,MAAMC,mBAAmB;AACzB,MAAMC,kBAAkB;AACxB,MAAMC,eAAe;AACrB,MAAMC,cAAc;AACpB,MAAMC,cAAc;AASpB,6BAAeV,KAAK,SAASW,kBAAkB,EAAEC,KAAK,EAAEC,KAAK,EAAEC,YAAY,EAAS;IAClF,MAAM,EAAEC,MAAM,EAAE,GAAGhB;IACnB,MAAMiB,iBAAiBD,CAAAA,mBAAAA,6BAAAA,OAAQE,IAAI,KAAI;IACvC,MAAMC,aAAahB,OAAO;IAE1B,sEAAsE;IACtE,MAAMiB,cAAc;IACpB,MAAMC,cAAc;IACpB,MAAMC,aAAaC,KAAKC,GAAG,CAAC,GAAGP,iBAAiBG,cAAcC;IAE9D,oFAAoF;IACpF,IAAI,CAACF,WAAWM,OAAO,IAAIT,QAAQ;QACjCA,OAAOU,KAAK,CAACnB,mBAAmBE,eAAeC,cAAcC;QAC7DQ,WAAWM,OAAO,GAAG;IACvB;IAEA,mCAAmC;IACnCvB,gBAAgB;QACd,OAAO;YACL,IAAIc,UAAUG,WAAWM,OAAO,EAAE;gBAChCT,OAAOU,KAAK,CAAClB;gBACbW,WAAWM,OAAO,GAAG;YACvB;QACF;IACF,GAAG;QAACT;KAAO;IAEX,MAAMW,eAAeb,MAAMc,KAAK,CAACb,cAAcA,eAAeO;IAC9D,MAAMO,aAAaf,MAAMgB,MAAM;IAC/B,MAAMC,cAAchB,eAAe;IACnC,MAAMiB,UAAUT,KAAKU,GAAG,CAAClB,eAAeO,YAAYO;IAEpD,qBACE,MAAC/B;QAAIoC,eAAc;QAASC,QAAQlB;;0BAElC,KAAClB;gBAAKqC,IAAI;gBAACC,OAAM;0BACdxB;;0BAEH,KAACd;gBAAKuC,QAAQ;0BAAE,IAAIC,MAAM,CAAChB,KAAKU,GAAG,CAAC,IAAIjB,CAAAA,mBAAAA,6BAAAA,OAAQwB,OAAO,KAAI;;0BAG3D,KAAC1C;gBAAIoC,eAAc;gBAASO,UAAU;0BACnC3B,MAAMgB,MAAM,KAAK,kBAChB,KAAC/B;oBAAKuC,QAAQ;8BAAC;qBAEfX,aAAae,GAAG,CAAC,CAACC,MAAMC,IACtB,iHAAiH;kCACjH,KAAC7C;kCAA6B4C,KAAKE,IAAI,IAAI;uBAAhC9B,eAAe6B;;0BAMhC,MAAC7C;gBAAKuC,QAAQ;;oBAAC;oBACNP;oBAAY;oBAAEC;oBAAQ;oBAAKH;oBAAW;oBAAiCzB,QAAQ,SAAS;oBAAM;;;;;AAI7G,GAAG"}
@@ -35,9 +35,7 @@ import { StreamingTerminal } from 'terminal-model';
35
35
  }
36
36
  // Return copy of all lines WITHOUT trimStart() or trimming blank lines
37
37
  // Preserves all whitespace, indentation, and blank lines
38
- return [
39
- ...this.allLines
40
- ];
38
+ return this.allLines.slice();
41
39
  }
42
40
  /**
43
41
  * Get the number of rendered lines.
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/OpenSource/node/spawn-term/src/lib/TerminalBuffer.ts"],"sourcesContent":["import { StreamingTerminal } from 'terminal-model';\n\n/**\n * Wrapper around terminal-model's StreamingTerminal 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 *\n * This implementation preserves whitespace and blank lines by NOT calling trimStart(),\n * which was the bug in the previous xterm-based implementation.\n */\nexport class TerminalBuffer {\n private terminal: StreamingTerminal;\n private allLines: string[] = [];\n\n constructor(_cols: number, _scrollback = 10000) {\n // terminal-model doesn't enforce column width during parsing\n // It preserves all content as-is\n this.terminal = new StreamingTerminal();\n\n // Listen for completed lines (when \\n is encountered)\n this.terminal.setLineReadyCallback(() => {\n const line = this.terminal.renderLine();\n this.terminal.reset();\n this.allLines.push(line);\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 this.terminal.write(data);\n }\n\n /**\n * Resize the terminal width.\n * terminal-model doesn't use column constraints, so this is a no-op for compatibility.\n */\n resize(_cols: number): void {\n // No-op - terminal-model doesn't enforce column width\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, with color codes preserved.\n *\n * CRITICAL: Unlike the xterm implementation, we do NOT call trimStart(),\n * which preserves legitimate indentation and blank lines.\n */\n getLines(): string[] {\n // Flush any pending content (incomplete line without \\n)\n if (this.terminal.hasContent()) {\n const line = this.terminal.renderLine();\n this.terminal.reset();\n this.allLines.push(line);\n }\n\n // Return copy of all lines WITHOUT trimStart() or trimming blank lines\n // Preserves all whitespace, indentation, and blank lines\n return [...this.allLines];\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 this.allLines = [];\n }\n}\n"],"names":["StreamingTerminal","TerminalBuffer","write","data","terminal","resize","_cols","getLines","hasContent","line","renderLine","reset","allLines","push","lineCount","length","dispose","_scrollback","setLineReadyCallback"],"mappings":"AAAA,SAASA,iBAAiB,QAAQ,iBAAiB;AAEnD;;;;;;;CAOC,GACD,OAAO,MAAMC;IAiBX;;;GAGC,GACDC,MAAMC,IAAqB,EAAQ;QACjC,IAAI,CAACC,QAAQ,CAACF,KAAK,CAACC;IACtB;IAEA;;;GAGC,GACDE,OAAOC,KAAa,EAAQ;IAC1B,sDAAsD;IACxD;IAEA;;;;;;;GAOC,GACDC,WAAqB;QACnB,yDAAyD;QACzD,IAAI,IAAI,CAACH,QAAQ,CAACI,UAAU,IAAI;YAC9B,MAAMC,OAAO,IAAI,CAACL,QAAQ,CAACM,UAAU;YACrC,IAAI,CAACN,QAAQ,CAACO,KAAK;YACnB,IAAI,CAACC,QAAQ,CAACC,IAAI,CAACJ;QACrB;QAEA,uEAAuE;QACvE,yDAAyD;QACzD,OAAO;eAAI,IAAI,CAACG,QAAQ;SAAC;IAC3B;IAEA;;GAEC,GACD,IAAIE,YAAoB;QACtB,OAAO,IAAI,CAACP,QAAQ,GAAGQ,MAAM;IAC/B;IAEA;;GAEC,GACDC,UAAgB;QACd,IAAI,CAACZ,QAAQ,CAACY,OAAO;QACrB,IAAI,CAACJ,QAAQ,GAAG,EAAE;IACpB;IA/DA,YAAYN,KAAa,EAAEW,cAAc,KAAK,CAAE;aAFxCL,WAAqB,EAAE;QAG7B,6DAA6D;QAC7D,iCAAiC;QACjC,IAAI,CAACR,QAAQ,GAAG,IAAIJ;QAEpB,sDAAsD;QACtD,IAAI,CAACI,QAAQ,CAACc,oBAAoB,CAAC;YACjC,MAAMT,OAAO,IAAI,CAACL,QAAQ,CAACM,UAAU;YACrC,IAAI,CAACN,QAAQ,CAACO,KAAK;YACnB,IAAI,CAACC,QAAQ,CAACC,IAAI,CAACJ;QACrB;IACF;AAqDF"}
1
+ {"version":3,"sources":["/Users/kevin/Dev/OpenSource/node/spawn-term/src/lib/TerminalBuffer.ts"],"sourcesContent":["import { StreamingTerminal } from 'terminal-model';\n\n/**\n * Wrapper around terminal-model's StreamingTerminal 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 *\n * This implementation preserves whitespace and blank lines by NOT calling trimStart(),\n * which was the bug in the previous xterm-based implementation.\n */\nexport class TerminalBuffer {\n private terminal: StreamingTerminal;\n private allLines: string[] = [];\n\n constructor(_cols: number, _scrollback = 10000) {\n // terminal-model doesn't enforce column width during parsing\n // It preserves all content as-is\n this.terminal = new StreamingTerminal();\n\n // Listen for completed lines (when \\n is encountered)\n this.terminal.setLineReadyCallback(() => {\n const line = this.terminal.renderLine();\n this.terminal.reset();\n this.allLines.push(line);\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 this.terminal.write(data);\n }\n\n /**\n * Resize the terminal width.\n * terminal-model doesn't use column constraints, so this is a no-op for compatibility.\n */\n resize(_cols: number): void {\n // No-op - terminal-model doesn't enforce column width\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, with color codes preserved.\n *\n * CRITICAL: Unlike the xterm implementation, we do NOT call trimStart(),\n * which preserves legitimate indentation and blank lines.\n */\n getLines(): string[] {\n // Flush any pending content (incomplete line without \\n)\n if (this.terminal.hasContent()) {\n const line = this.terminal.renderLine();\n this.terminal.reset();\n this.allLines.push(line);\n }\n\n // Return copy of all lines WITHOUT trimStart() or trimming blank lines\n // Preserves all whitespace, indentation, and blank lines\n return this.allLines.slice();\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 this.allLines = [];\n }\n}\n"],"names":["StreamingTerminal","TerminalBuffer","write","data","terminal","resize","_cols","getLines","hasContent","line","renderLine","reset","allLines","push","slice","lineCount","length","dispose","_scrollback","setLineReadyCallback"],"mappings":"AAAA,SAASA,iBAAiB,QAAQ,iBAAiB;AAEnD;;;;;;;CAOC,GACD,OAAO,MAAMC;IAiBX;;;GAGC,GACDC,MAAMC,IAAqB,EAAQ;QACjC,IAAI,CAACC,QAAQ,CAACF,KAAK,CAACC;IACtB;IAEA;;;GAGC,GACDE,OAAOC,KAAa,EAAQ;IAC1B,sDAAsD;IACxD;IAEA;;;;;;;GAOC,GACDC,WAAqB;QACnB,yDAAyD;QACzD,IAAI,IAAI,CAACH,QAAQ,CAACI,UAAU,IAAI;YAC9B,MAAMC,OAAO,IAAI,CAACL,QAAQ,CAACM,UAAU;YACrC,IAAI,CAACN,QAAQ,CAACO,KAAK;YACnB,IAAI,CAACC,QAAQ,CAACC,IAAI,CAACJ;QACrB;QAEA,uEAAuE;QACvE,yDAAyD;QACzD,OAAO,IAAI,CAACG,QAAQ,CAACE,KAAK;IAC5B;IAEA;;GAEC,GACD,IAAIC,YAAoB;QACtB,OAAO,IAAI,CAACR,QAAQ,GAAGS,MAAM;IAC/B;IAEA;;GAEC,GACDC,UAAgB;QACd,IAAI,CAACb,QAAQ,CAACa,OAAO;QACrB,IAAI,CAACL,QAAQ,GAAG,EAAE;IACpB;IA/DA,YAAYN,KAAa,EAAEY,cAAc,KAAK,CAAE;aAFxCN,WAAqB,EAAE;QAG7B,6DAA6D;QAC7D,iCAAiC;QACjC,IAAI,CAACR,QAAQ,GAAG,IAAIJ;QAEpB,sDAAsD;QACtD,IAAI,CAACI,QAAQ,CAACe,oBAAoB,CAAC;YACjC,MAAMV,OAAO,IAAI,CAACL,QAAQ,CAACM,UAAU;YACrC,IAAI,CAACN,QAAQ,CAACO,KAAK;YACnB,IAAI,CAACC,QAAQ,CAACC,IAAI,CAACJ;QACrB;IACF;AAqDF"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "spawn-term",
3
- "version": "3.5.1",
3
+ "version": "3.5.3",
4
4
  "description": "Formats spawn with for terminal grouping",
5
5
  "keywords": [
6
6
  "spawn",