spawn-term 3.4.2 → 3.5.0

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.
@@ -8,7 +8,15 @@ Object.defineProperty(exports, "TerminalBuffer", {
8
8
  return TerminalBuffer;
9
9
  }
10
10
  });
11
- var _headless = /*#__PURE__*/ _interop_require_wildcard(require("@xterm/headless"));
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
+ }
12
20
  function _class_call_check(instance, Constructor) {
13
21
  if (!(instance instanceof Constructor)) {
14
22
  throw new TypeError("Cannot call a class as a function");
@@ -28,152 +36,38 @@ function _create_class(Constructor, protoProps, staticProps) {
28
36
  if (staticProps) _defineProperties(Constructor, staticProps);
29
37
  return Constructor;
30
38
  }
31
- function _define_property(obj, key, value) {
32
- if (key in obj) {
33
- Object.defineProperty(obj, key, {
34
- value: value,
35
- enumerable: true,
36
- configurable: true,
37
- writable: true
38
- });
39
- } else {
40
- obj[key] = value;
41
- }
42
- return obj;
43
- }
44
- function _getRequireWildcardCache(nodeInterop) {
45
- if (typeof WeakMap !== "function") return null;
46
- var cacheBabelInterop = new WeakMap();
47
- var cacheNodeInterop = new WeakMap();
48
- return (_getRequireWildcardCache = function(nodeInterop) {
49
- return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
50
- })(nodeInterop);
51
- }
52
- function _interop_require_wildcard(obj, nodeInterop) {
53
- if (!nodeInterop && obj && obj.__esModule) {
54
- return obj;
55
- }
56
- if (obj === null || typeof obj !== "object" && typeof obj !== "function") {
57
- return {
58
- default: obj
59
- };
60
- }
61
- var cache = _getRequireWildcardCache(nodeInterop);
62
- if (cache && cache.has(obj)) {
63
- return cache.get(obj);
64
- }
65
- var newObj = {
66
- __proto__: null
67
- };
68
- var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
69
- for(var key in obj){
70
- if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) {
71
- var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;
72
- if (desc && (desc.get || desc.set)) {
73
- Object.defineProperty(newObj, key, desc);
74
- } else {
75
- newObj[key] = obj[key];
76
- }
77
- }
78
- }
79
- newObj.default = obj;
80
- if (cache) {
81
- cache.set(obj, newObj);
82
- }
83
- return newObj;
39
+ function _iterable_to_array(iter) {
40
+ if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter);
84
41
  }
85
- function _object_spread(target) {
86
- for(var i = 1; i < arguments.length; i++){
87
- var source = arguments[i] != null ? arguments[i] : {};
88
- var ownKeys = Object.keys(source);
89
- if (typeof Object.getOwnPropertySymbols === "function") {
90
- ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function(sym) {
91
- return Object.getOwnPropertyDescriptor(source, sym).enumerable;
92
- }));
93
- }
94
- ownKeys.forEach(function(key) {
95
- _define_property(target, key, source[key]);
96
- });
97
- }
98
- return target;
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.");
99
44
  }
100
- var _xterm_default;
101
- // Handle both ESM and CJS module formats
102
- var Terminal = _headless.Terminal || ((_xterm_default = _headless.default) === null || _xterm_default === void 0 ? void 0 : _xterm_default.Terminal);
103
- // ANSI color mode constants from xterm.js
104
- var COLOR_MODE_DEFAULT = 0;
105
- var COLOR_MODE_16 = 16777216; // 0x1000000 - 16 color palette (0-15)
106
- var COLOR_MODE_256 = 33554432; // 0x2000000 - 256 color palette
107
- var COLOR_MODE_RGB = 50331648; // 0x3000000 - 24-bit RGB
108
- var DEFAULT_STYLE = {
109
- fg: -1,
110
- fgMode: COLOR_MODE_DEFAULT,
111
- bg: -1,
112
- bgMode: COLOR_MODE_DEFAULT,
113
- bold: false,
114
- dim: false,
115
- italic: false,
116
- underline: false,
117
- inverse: false,
118
- strikethrough: false
119
- };
120
- function styleEquals(a, b) {
121
- return a.fg === b.fg && a.fgMode === b.fgMode && a.bg === b.bg && a.bgMode === b.bgMode && a.bold === b.bold && a.dim === b.dim && a.italic === b.italic && a.underline === b.underline && a.inverse === b.inverse && a.strikethrough === b.strikethrough;
45
+ function _to_consumable_array(arr) {
46
+ return _array_without_holes(arr) || _iterable_to_array(arr) || _unsupported_iterable_to_array(arr) || _non_iterable_spread();
122
47
  }
123
- function buildAnsiCode(style) {
124
- var codes = [];
125
- // Attributes
126
- if (style.bold) codes.push(1);
127
- if (style.dim) codes.push(2);
128
- if (style.italic) codes.push(3);
129
- if (style.underline) codes.push(4);
130
- if (style.inverse) codes.push(7);
131
- if (style.strikethrough) codes.push(9);
132
- // Foreground color
133
- if (style.fgMode === COLOR_MODE_16) {
134
- // 16-color palette: 0-7 are 30-37, 8-15 are 90-97
135
- if (style.fg < 8) {
136
- codes.push(30 + style.fg);
137
- } else {
138
- codes.push(90 + (style.fg - 8));
139
- }
140
- } else if (style.fgMode === COLOR_MODE_256) {
141
- codes.push(38, 5, style.fg);
142
- } else if (style.fgMode === COLOR_MODE_RGB) {
143
- // RGB is encoded in the color value
144
- var r = style.fg >> 16 & 0xff;
145
- var g = style.fg >> 8 & 0xff;
146
- var b = style.fg & 0xff;
147
- codes.push(38, 2, r, g, b);
148
- }
149
- // Background color
150
- if (style.bgMode === COLOR_MODE_16) {
151
- if (style.bg < 8) {
152
- codes.push(40 + style.bg);
153
- } else {
154
- codes.push(100 + (style.bg - 8));
155
- }
156
- } else if (style.bgMode === COLOR_MODE_256) {
157
- codes.push(48, 5, style.bg);
158
- } else if (style.bgMode === COLOR_MODE_RGB) {
159
- var r1 = style.bg >> 16 & 0xff;
160
- var g1 = style.bg >> 8 & 0xff;
161
- var b1 = style.bg & 0xff;
162
- codes.push(48, 2, r1, g1, b1);
163
- }
164
- if (codes.length === 0) return '';
165
- return "\x1b[".concat(codes.join(';'), "m");
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);
166
55
  }
167
56
  var TerminalBuffer = /*#__PURE__*/ function() {
168
57
  "use strict";
169
- function TerminalBuffer(cols) {
170
- var scrollback = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : 10000;
58
+ function TerminalBuffer(_cols) {
59
+ var _this = this;
60
+ var _scrollback = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : 10000;
171
61
  _class_call_check(this, TerminalBuffer);
172
- this.terminal = new Terminal({
173
- cols: cols,
174
- rows: 50,
175
- scrollback: scrollback,
176
- allowProposedApi: true
62
+ this.allLines = [];
63
+ // terminal-model doesn't enforce column width during parsing
64
+ // It preserves all content as-is
65
+ this.terminal = new _terminalmodel.StreamingTerminal();
66
+ // Listen for completed lines (when \n is encountered)
67
+ this.terminal.setLineReadyCallback(function() {
68
+ var line = _this.terminal.renderLine();
69
+ _this.terminal.reset();
70
+ _this.allLines.push(line);
177
71
  });
178
72
  }
179
73
  var _proto = TerminalBuffer.prototype;
@@ -181,79 +75,31 @@ var TerminalBuffer = /*#__PURE__*/ function() {
181
75
  * Write raw data to the terminal buffer.
182
76
  * The terminal interprets all ANSI sequences automatically.
183
77
  */ _proto.write = function write(data) {
184
- var str = typeof data === 'string' ? data : data.toString('utf8');
185
- this.terminal.write(str);
78
+ this.terminal.write(data);
186
79
  };
187
80
  /**
188
81
  * Resize the terminal width.
189
- */ _proto.resize = function resize(cols) {
190
- this.terminal.resize(cols, this.terminal.rows);
82
+ * terminal-model doesn't use column constraints, so this is a no-op for compatibility.
83
+ */ _proto.resize = function resize(_cols) {
84
+ // No-op - terminal-model doesn't enforce column width
191
85
  };
192
86
  /**
193
87
  * Extract the rendered lines from the terminal buffer.
194
88
  * This returns the actual visible content after all ANSI sequences
195
89
  * have been processed, with color codes preserved.
90
+ *
91
+ * CRITICAL: Unlike the xterm implementation, we do NOT call trimStart(),
92
+ * which preserves legitimate indentation and blank lines.
196
93
  */ _proto.getLines = function getLines() {
197
- var buffer = this.terminal.buffer.active;
198
- var lines = [];
199
- for(var i = 0; i < buffer.length; i++){
200
- var bufferLine = buffer.getLine(i);
201
- if (!bufferLine) continue;
202
- var result = '';
203
- var currentStyle = _object_spread({}, DEFAULT_STYLE);
204
- var _hasContent = false;
205
- // First pass: find the last non-empty cell to know where content ends
206
- var lastContentIndex = -1;
207
- for(var j = bufferLine.length - 1; j >= 0; j--){
208
- var cell = bufferLine.getCell(j);
209
- if (cell && cell.getChars()) {
210
- lastContentIndex = j;
211
- break;
212
- }
213
- }
214
- // Second pass: build the line with ANSI codes
215
- for(var j1 = 0; j1 <= lastContentIndex; j1++){
216
- var cell1 = bufferLine.getCell(j1);
217
- if (!cell1) continue;
218
- var char = cell1.getChars();
219
- var cellStyle = {
220
- fg: cell1.getFgColor(),
221
- fgMode: cell1.getFgColorMode(),
222
- bg: cell1.getBgColor(),
223
- bgMode: cell1.getBgColorMode(),
224
- bold: cell1.isBold() !== 0,
225
- dim: cell1.isDim() !== 0,
226
- italic: cell1.isItalic() !== 0,
227
- underline: cell1.isUnderline() !== 0,
228
- inverse: cell1.isInverse() !== 0,
229
- strikethrough: cell1.isStrikethrough() !== 0
230
- };
231
- // Check if style changed
232
- if (!styleEquals(cellStyle, currentStyle)) {
233
- // Reset if going back to default, otherwise emit new style
234
- if (styleEquals(cellStyle, DEFAULT_STYLE)) {
235
- result += '\x1b[0m';
236
- } else {
237
- // If we had styling before, reset first for clean transition
238
- if (!styleEquals(currentStyle, DEFAULT_STYLE)) {
239
- result += '\x1b[0m';
240
- }
241
- result += buildAnsiCode(cellStyle);
242
- }
243
- currentStyle = cellStyle;
244
- }
245
- result += char || ' ';
246
- if (char) _hasContent = true;
247
- }
248
- // Reset at end of line if we had styling
249
- if (!styleEquals(currentStyle, DEFAULT_STYLE)) {
250
- result += '\x1b[0m';
251
- }
252
- // Trim leading whitespace - tools like ncu/npm use cursor positioning
253
- // which creates lines with leading spaces when interpreted by xterm
254
- lines.push(result.trimStart());
94
+ // Flush any pending content (incomplete line without \n)
95
+ if (this.terminal.hasContent()) {
96
+ var line = this.terminal.renderLine();
97
+ this.terminal.reset();
98
+ this.allLines.push(line);
255
99
  }
256
- // Trim trailing empty lines
100
+ // Return copy of all lines WITHOUT trimStart() - preserves whitespace
101
+ var lines = _to_consumable_array(this.allLines);
102
+ // Trim trailing empty lines only
257
103
  while(lines.length > 0 && lines[lines.length - 1] === ''){
258
104
  lines.pop();
259
105
  }
@@ -263,6 +109,7 @@ var TerminalBuffer = /*#__PURE__*/ function() {
263
109
  * Clean up terminal resources.
264
110
  */ _proto.dispose = function dispose() {
265
111
  this.terminal.dispose();
112
+ this.allLines = [];
266
113
  };
267
114
  _create_class(TerminalBuffer, [
268
115
  {
@@ -1 +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// ANSI color mode constants from xterm.js\nconst COLOR_MODE_DEFAULT = 0;\nconst COLOR_MODE_16 = 16777216; // 0x1000000 - 16 color palette (0-15)\nconst COLOR_MODE_256 = 33554432; // 0x2000000 - 256 color palette\nconst COLOR_MODE_RGB = 50331648; // 0x3000000 - 24-bit RGB\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 */\n// Cell attribute state for tracking changes\ninterface CellStyle {\n fg: number;\n fgMode: number;\n bg: number;\n bgMode: number;\n bold: boolean;\n dim: boolean;\n italic: boolean;\n underline: boolean;\n inverse: boolean;\n strikethrough: boolean;\n}\n\nconst DEFAULT_STYLE: CellStyle = {\n fg: -1,\n fgMode: COLOR_MODE_DEFAULT,\n bg: -1,\n bgMode: COLOR_MODE_DEFAULT,\n bold: false,\n dim: false,\n italic: false,\n underline: false,\n inverse: false,\n strikethrough: false,\n};\n\nfunction styleEquals(a: CellStyle, b: CellStyle): boolean {\n return a.fg === b.fg && a.fgMode === b.fgMode && a.bg === b.bg && a.bgMode === b.bgMode && a.bold === b.bold && a.dim === b.dim && a.italic === b.italic && a.underline === b.underline && a.inverse === b.inverse && a.strikethrough === b.strikethrough;\n}\n\nfunction buildAnsiCode(style: CellStyle): string {\n const codes: number[] = [];\n\n // Attributes\n if (style.bold) codes.push(1);\n if (style.dim) codes.push(2);\n if (style.italic) codes.push(3);\n if (style.underline) codes.push(4);\n if (style.inverse) codes.push(7);\n if (style.strikethrough) codes.push(9);\n\n // Foreground color\n if (style.fgMode === COLOR_MODE_16) {\n // 16-color palette: 0-7 are 30-37, 8-15 are 90-97\n if (style.fg < 8) {\n codes.push(30 + style.fg);\n } else {\n codes.push(90 + (style.fg - 8));\n }\n } else if (style.fgMode === COLOR_MODE_256) {\n codes.push(38, 5, style.fg);\n } else if (style.fgMode === COLOR_MODE_RGB) {\n // RGB is encoded in the color value\n const r = (style.fg >> 16) & 0xff;\n const g = (style.fg >> 8) & 0xff;\n const b = style.fg & 0xff;\n codes.push(38, 2, r, g, b);\n }\n\n // Background color\n if (style.bgMode === COLOR_MODE_16) {\n if (style.bg < 8) {\n codes.push(40 + style.bg);\n } else {\n codes.push(100 + (style.bg - 8));\n }\n } else if (style.bgMode === COLOR_MODE_256) {\n codes.push(48, 5, style.bg);\n } else if (style.bgMode === COLOR_MODE_RGB) {\n const r = (style.bg >> 16) & 0xff;\n const g = (style.bg >> 8) & 0xff;\n const b = style.bg & 0xff;\n codes.push(48, 2, r, g, b);\n }\n\n if (codes.length === 0) return '';\n return `\\x1b[${codes.join(';')}m`;\n}\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, with color codes preserved.\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 bufferLine = buffer.getLine(i);\n if (!bufferLine) continue;\n\n let result = '';\n let currentStyle: CellStyle = { ...DEFAULT_STYLE };\n let _hasContent = false;\n\n // First pass: find the last non-empty cell to know where content ends\n let lastContentIndex = -1;\n for (let j = bufferLine.length - 1; j >= 0; j--) {\n const cell = bufferLine.getCell(j);\n if (cell && cell.getChars()) {\n lastContentIndex = j;\n break;\n }\n }\n\n // Second pass: build the line with ANSI codes\n for (let j = 0; j <= lastContentIndex; j++) {\n const cell = bufferLine.getCell(j);\n if (!cell) continue;\n\n const char = cell.getChars();\n const cellStyle: CellStyle = {\n fg: cell.getFgColor(),\n fgMode: cell.getFgColorMode(),\n bg: cell.getBgColor(),\n bgMode: cell.getBgColorMode(),\n bold: cell.isBold() !== 0,\n dim: cell.isDim() !== 0,\n italic: cell.isItalic() !== 0,\n underline: cell.isUnderline() !== 0,\n inverse: cell.isInverse() !== 0,\n strikethrough: cell.isStrikethrough() !== 0,\n };\n\n // Check if style changed\n if (!styleEquals(cellStyle, currentStyle)) {\n // Reset if going back to default, otherwise emit new style\n if (styleEquals(cellStyle, DEFAULT_STYLE)) {\n result += '\\x1b[0m';\n } else {\n // If we had styling before, reset first for clean transition\n if (!styleEquals(currentStyle, DEFAULT_STYLE)) {\n result += '\\x1b[0m';\n }\n result += buildAnsiCode(cellStyle);\n }\n currentStyle = cellStyle;\n }\n\n result += char || ' ';\n if (char) _hasContent = true;\n }\n\n // Reset at end of line if we had styling\n if (!styleEquals(currentStyle, DEFAULT_STYLE)) {\n result += '\\x1b[0m';\n }\n\n // Trim leading whitespace - tools like ncu/npm use cursor positioning\n // which creates lines with leading spaces when interpreted by xterm\n lines.push(result.trimStart());\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","COLOR_MODE_DEFAULT","COLOR_MODE_16","COLOR_MODE_256","COLOR_MODE_RGB","DEFAULT_STYLE","fg","fgMode","bg","bgMode","bold","dim","italic","underline","inverse","strikethrough","styleEquals","a","b","buildAnsiCode","style","codes","push","r","g","length","join","cols","scrollback","terminal","rows","allowProposedApi","write","data","str","toString","resize","getLines","buffer","active","lines","i","bufferLine","getLine","result","currentStyle","_hasContent","lastContentIndex","j","cell","getCell","getChars","char","cellStyle","getFgColor","getFgColorMode","getBgColor","getBgColorMode","isBold","isDim","isItalic","isUnderline","isInverse","isStrikethrough","trimStart","pop","dispose","lineCount"],"mappings":"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"}
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() - preserves whitespace\n const lines = [...this.allLines];\n\n // Trim trailing empty lines only\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 this.allLines = [];\n }\n}\n"],"names":["TerminalBuffer","_cols","_scrollback","allLines","terminal","StreamingTerminal","setLineReadyCallback","line","renderLine","reset","push","write","data","resize","getLines","hasContent","lines","length","pop","dispose","lineCount"],"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,QAiBC,GAjBDA,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,sEAAsE;QACtE,IAAMS,QAAS,qBAAG,IAAI,CAACb,QAAQ;QAE/B,iCAAiC;QACjC,MAAOa,MAAMC,MAAM,GAAG,KAAKD,KAAK,CAACA,MAAMC,MAAM,GAAG,EAAE,KAAK,GAAI;YACzDD,MAAME,GAAG;QACX;QAEA,OAAOF;IACT;IASA;;GAEC,GACDG,OAAAA,OAGC,GAHDA,SAAAA;QACE,IAAI,CAACf,QAAQ,CAACe,OAAO;QACrB,IAAI,CAAChB,QAAQ,GAAG,EAAE;IACpB;kBAzEWH;;YA+DPoB,KAAAA;iBAAJ,AAHA;;GAEC,GACD;gBACE,OAAO,IAAI,CAACN,QAAQ,GAAGG,MAAM;YAC/B;;;WAjEWjB"}
@@ -1,6 +1,15 @@
1
+ /**
2
+ * Wrapper around terminal-model's StreamingTerminal that provides a virtual terminal buffer.
3
+ * Interprets ANSI escape sequences (cursor movement, line clearing, etc.) to produce
4
+ * the actual rendered output rather than raw intermediate states.
5
+ *
6
+ * This implementation preserves whitespace and blank lines by NOT calling trimStart(),
7
+ * which was the bug in the previous xterm-based implementation.
8
+ */
1
9
  export declare class TerminalBuffer {
2
10
  private terminal;
3
- constructor(cols: number, scrollback?: number);
11
+ private allLines;
12
+ constructor(_cols: number, _scrollback?: number);
4
13
  /**
5
14
  * Write raw data to the terminal buffer.
6
15
  * The terminal interprets all ANSI sequences automatically.
@@ -8,12 +17,16 @@ export declare class TerminalBuffer {
8
17
  write(data: string | Buffer): void;
9
18
  /**
10
19
  * Resize the terminal width.
20
+ * terminal-model doesn't use column constraints, so this is a no-op for compatibility.
11
21
  */
12
- resize(cols: number): void;
22
+ resize(_cols: number): void;
13
23
  /**
14
24
  * Extract the rendered lines from the terminal buffer.
15
25
  * This returns the actual visible content after all ANSI sequences
16
26
  * have been processed, with color codes preserved.
27
+ *
28
+ * CRITICAL: Unlike the xterm implementation, we do NOT call trimStart(),
29
+ * which preserves legitimate indentation and blank lines.
17
30
  */
18
31
  getLines(): string[];
19
32
  /**
@@ -1,151 +1,43 @@
1
- var _xterm_default;
2
- import * as xterm from '@xterm/headless';
3
- // Handle both ESM and CJS module formats
4
- const Terminal = xterm.Terminal || ((_xterm_default = xterm.default) === null || _xterm_default === void 0 ? void 0 : _xterm_default.Terminal);
5
- // ANSI color mode constants from xterm.js
6
- const COLOR_MODE_DEFAULT = 0;
7
- const COLOR_MODE_16 = 16777216; // 0x1000000 - 16 color palette (0-15)
8
- const COLOR_MODE_256 = 33554432; // 0x2000000 - 256 color palette
9
- const COLOR_MODE_RGB = 50331648; // 0x3000000 - 24-bit RGB
10
- const DEFAULT_STYLE = {
11
- fg: -1,
12
- fgMode: COLOR_MODE_DEFAULT,
13
- bg: -1,
14
- bgMode: COLOR_MODE_DEFAULT,
15
- bold: false,
16
- dim: false,
17
- italic: false,
18
- underline: false,
19
- inverse: false,
20
- strikethrough: false
21
- };
22
- function styleEquals(a, b) {
23
- return a.fg === b.fg && a.fgMode === b.fgMode && a.bg === b.bg && a.bgMode === b.bgMode && a.bold === b.bold && a.dim === b.dim && a.italic === b.italic && a.underline === b.underline && a.inverse === b.inverse && a.strikethrough === b.strikethrough;
24
- }
25
- function buildAnsiCode(style) {
26
- const codes = [];
27
- // Attributes
28
- if (style.bold) codes.push(1);
29
- if (style.dim) codes.push(2);
30
- if (style.italic) codes.push(3);
31
- if (style.underline) codes.push(4);
32
- if (style.inverse) codes.push(7);
33
- if (style.strikethrough) codes.push(9);
34
- // Foreground color
35
- if (style.fgMode === COLOR_MODE_16) {
36
- // 16-color palette: 0-7 are 30-37, 8-15 are 90-97
37
- if (style.fg < 8) {
38
- codes.push(30 + style.fg);
39
- } else {
40
- codes.push(90 + (style.fg - 8));
41
- }
42
- } else if (style.fgMode === COLOR_MODE_256) {
43
- codes.push(38, 5, style.fg);
44
- } else if (style.fgMode === COLOR_MODE_RGB) {
45
- // RGB is encoded in the color value
46
- const r = style.fg >> 16 & 0xff;
47
- const g = style.fg >> 8 & 0xff;
48
- const b = style.fg & 0xff;
49
- codes.push(38, 2, r, g, b);
50
- }
51
- // Background color
52
- if (style.bgMode === COLOR_MODE_16) {
53
- if (style.bg < 8) {
54
- codes.push(40 + style.bg);
55
- } else {
56
- codes.push(100 + (style.bg - 8));
57
- }
58
- } else if (style.bgMode === COLOR_MODE_256) {
59
- codes.push(48, 5, style.bg);
60
- } else if (style.bgMode === COLOR_MODE_RGB) {
61
- const r = style.bg >> 16 & 0xff;
62
- const g = style.bg >> 8 & 0xff;
63
- const b = style.bg & 0xff;
64
- codes.push(48, 2, r, g, b);
65
- }
66
- if (codes.length === 0) return '';
67
- return `\x1b[${codes.join(';')}m`;
68
- }
69
- export class TerminalBuffer {
1
+ import { StreamingTerminal } from 'terminal-model';
2
+ /**
3
+ * Wrapper around terminal-model's StreamingTerminal that provides a virtual terminal buffer.
4
+ * Interprets ANSI escape sequences (cursor movement, line clearing, etc.) to produce
5
+ * the actual rendered output rather than raw intermediate states.
6
+ *
7
+ * This implementation preserves whitespace and blank lines by NOT calling trimStart(),
8
+ * which was the bug in the previous xterm-based implementation.
9
+ */ export class TerminalBuffer {
70
10
  /**
71
11
  * Write raw data to the terminal buffer.
72
12
  * The terminal interprets all ANSI sequences automatically.
73
13
  */ write(data) {
74
- const str = typeof data === 'string' ? data : data.toString('utf8');
75
- this.terminal.write(str);
14
+ this.terminal.write(data);
76
15
  }
77
16
  /**
78
17
  * Resize the terminal width.
79
- */ resize(cols) {
80
- this.terminal.resize(cols, this.terminal.rows);
18
+ * terminal-model doesn't use column constraints, so this is a no-op for compatibility.
19
+ */ resize(_cols) {
20
+ // No-op - terminal-model doesn't enforce column width
81
21
  }
82
22
  /**
83
23
  * Extract the rendered lines from the terminal buffer.
84
24
  * This returns the actual visible content after all ANSI sequences
85
25
  * have been processed, with color codes preserved.
26
+ *
27
+ * CRITICAL: Unlike the xterm implementation, we do NOT call trimStart(),
28
+ * which preserves legitimate indentation and blank lines.
86
29
  */ getLines() {
87
- const buffer = this.terminal.buffer.active;
88
- const lines = [];
89
- for(let i = 0; i < buffer.length; i++){
90
- const bufferLine = buffer.getLine(i);
91
- if (!bufferLine) continue;
92
- let result = '';
93
- let currentStyle = {
94
- ...DEFAULT_STYLE
95
- };
96
- let _hasContent = false;
97
- // First pass: find the last non-empty cell to know where content ends
98
- let lastContentIndex = -1;
99
- for(let j = bufferLine.length - 1; j >= 0; j--){
100
- const cell = bufferLine.getCell(j);
101
- if (cell && cell.getChars()) {
102
- lastContentIndex = j;
103
- break;
104
- }
105
- }
106
- // Second pass: build the line with ANSI codes
107
- for(let j = 0; j <= lastContentIndex; j++){
108
- const cell = bufferLine.getCell(j);
109
- if (!cell) continue;
110
- const char = cell.getChars();
111
- const cellStyle = {
112
- fg: cell.getFgColor(),
113
- fgMode: cell.getFgColorMode(),
114
- bg: cell.getBgColor(),
115
- bgMode: cell.getBgColorMode(),
116
- bold: cell.isBold() !== 0,
117
- dim: cell.isDim() !== 0,
118
- italic: cell.isItalic() !== 0,
119
- underline: cell.isUnderline() !== 0,
120
- inverse: cell.isInverse() !== 0,
121
- strikethrough: cell.isStrikethrough() !== 0
122
- };
123
- // Check if style changed
124
- if (!styleEquals(cellStyle, currentStyle)) {
125
- // Reset if going back to default, otherwise emit new style
126
- if (styleEquals(cellStyle, DEFAULT_STYLE)) {
127
- result += '\x1b[0m';
128
- } else {
129
- // If we had styling before, reset first for clean transition
130
- if (!styleEquals(currentStyle, DEFAULT_STYLE)) {
131
- result += '\x1b[0m';
132
- }
133
- result += buildAnsiCode(cellStyle);
134
- }
135
- currentStyle = cellStyle;
136
- }
137
- result += char || ' ';
138
- if (char) _hasContent = true;
139
- }
140
- // Reset at end of line if we had styling
141
- if (!styleEquals(currentStyle, DEFAULT_STYLE)) {
142
- result += '\x1b[0m';
143
- }
144
- // Trim leading whitespace - tools like ncu/npm use cursor positioning
145
- // which creates lines with leading spaces when interpreted by xterm
146
- lines.push(result.trimStart());
30
+ // Flush any pending content (incomplete line without \n)
31
+ if (this.terminal.hasContent()) {
32
+ const line = this.terminal.renderLine();
33
+ this.terminal.reset();
34
+ this.allLines.push(line);
147
35
  }
148
- // Trim trailing empty lines
36
+ // Return copy of all lines WITHOUT trimStart() - preserves whitespace
37
+ const lines = [
38
+ ...this.allLines
39
+ ];
40
+ // Trim trailing empty lines only
149
41
  while(lines.length > 0 && lines[lines.length - 1] === ''){
150
42
  lines.pop();
151
43
  }
@@ -160,13 +52,18 @@ export class TerminalBuffer {
160
52
  * Clean up terminal resources.
161
53
  */ dispose() {
162
54
  this.terminal.dispose();
55
+ this.allLines = [];
163
56
  }
164
- constructor(cols, scrollback = 10000){
165
- this.terminal = new Terminal({
166
- cols,
167
- rows: 50,
168
- scrollback,
169
- allowProposedApi: true
57
+ constructor(_cols, _scrollback = 10000){
58
+ this.allLines = [];
59
+ // terminal-model doesn't enforce column width during parsing
60
+ // It preserves all content as-is
61
+ this.terminal = new StreamingTerminal();
62
+ // Listen for completed lines (when \n is encountered)
63
+ this.terminal.setLineReadyCallback(()=>{
64
+ const line = this.terminal.renderLine();
65
+ this.terminal.reset();
66
+ this.allLines.push(line);
170
67
  });
171
68
  }
172
69
  }
@@ -1 +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// ANSI color mode constants from xterm.js\nconst COLOR_MODE_DEFAULT = 0;\nconst COLOR_MODE_16 = 16777216; // 0x1000000 - 16 color palette (0-15)\nconst COLOR_MODE_256 = 33554432; // 0x2000000 - 256 color palette\nconst COLOR_MODE_RGB = 50331648; // 0x3000000 - 24-bit RGB\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 */\n// Cell attribute state for tracking changes\ninterface CellStyle {\n fg: number;\n fgMode: number;\n bg: number;\n bgMode: number;\n bold: boolean;\n dim: boolean;\n italic: boolean;\n underline: boolean;\n inverse: boolean;\n strikethrough: boolean;\n}\n\nconst DEFAULT_STYLE: CellStyle = {\n fg: -1,\n fgMode: COLOR_MODE_DEFAULT,\n bg: -1,\n bgMode: COLOR_MODE_DEFAULT,\n bold: false,\n dim: false,\n italic: false,\n underline: false,\n inverse: false,\n strikethrough: false,\n};\n\nfunction styleEquals(a: CellStyle, b: CellStyle): boolean {\n return a.fg === b.fg && a.fgMode === b.fgMode && a.bg === b.bg && a.bgMode === b.bgMode && a.bold === b.bold && a.dim === b.dim && a.italic === b.italic && a.underline === b.underline && a.inverse === b.inverse && a.strikethrough === b.strikethrough;\n}\n\nfunction buildAnsiCode(style: CellStyle): string {\n const codes: number[] = [];\n\n // Attributes\n if (style.bold) codes.push(1);\n if (style.dim) codes.push(2);\n if (style.italic) codes.push(3);\n if (style.underline) codes.push(4);\n if (style.inverse) codes.push(7);\n if (style.strikethrough) codes.push(9);\n\n // Foreground color\n if (style.fgMode === COLOR_MODE_16) {\n // 16-color palette: 0-7 are 30-37, 8-15 are 90-97\n if (style.fg < 8) {\n codes.push(30 + style.fg);\n } else {\n codes.push(90 + (style.fg - 8));\n }\n } else if (style.fgMode === COLOR_MODE_256) {\n codes.push(38, 5, style.fg);\n } else if (style.fgMode === COLOR_MODE_RGB) {\n // RGB is encoded in the color value\n const r = (style.fg >> 16) & 0xff;\n const g = (style.fg >> 8) & 0xff;\n const b = style.fg & 0xff;\n codes.push(38, 2, r, g, b);\n }\n\n // Background color\n if (style.bgMode === COLOR_MODE_16) {\n if (style.bg < 8) {\n codes.push(40 + style.bg);\n } else {\n codes.push(100 + (style.bg - 8));\n }\n } else if (style.bgMode === COLOR_MODE_256) {\n codes.push(48, 5, style.bg);\n } else if (style.bgMode === COLOR_MODE_RGB) {\n const r = (style.bg >> 16) & 0xff;\n const g = (style.bg >> 8) & 0xff;\n const b = style.bg & 0xff;\n codes.push(48, 2, r, g, b);\n }\n\n if (codes.length === 0) return '';\n return `\\x1b[${codes.join(';')}m`;\n}\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, with color codes preserved.\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 bufferLine = buffer.getLine(i);\n if (!bufferLine) continue;\n\n let result = '';\n let currentStyle: CellStyle = { ...DEFAULT_STYLE };\n let _hasContent = false;\n\n // First pass: find the last non-empty cell to know where content ends\n let lastContentIndex = -1;\n for (let j = bufferLine.length - 1; j >= 0; j--) {\n const cell = bufferLine.getCell(j);\n if (cell && cell.getChars()) {\n lastContentIndex = j;\n break;\n }\n }\n\n // Second pass: build the line with ANSI codes\n for (let j = 0; j <= lastContentIndex; j++) {\n const cell = bufferLine.getCell(j);\n if (!cell) continue;\n\n const char = cell.getChars();\n const cellStyle: CellStyle = {\n fg: cell.getFgColor(),\n fgMode: cell.getFgColorMode(),\n bg: cell.getBgColor(),\n bgMode: cell.getBgColorMode(),\n bold: cell.isBold() !== 0,\n dim: cell.isDim() !== 0,\n italic: cell.isItalic() !== 0,\n underline: cell.isUnderline() !== 0,\n inverse: cell.isInverse() !== 0,\n strikethrough: cell.isStrikethrough() !== 0,\n };\n\n // Check if style changed\n if (!styleEquals(cellStyle, currentStyle)) {\n // Reset if going back to default, otherwise emit new style\n if (styleEquals(cellStyle, DEFAULT_STYLE)) {\n result += '\\x1b[0m';\n } else {\n // If we had styling before, reset first for clean transition\n if (!styleEquals(currentStyle, DEFAULT_STYLE)) {\n result += '\\x1b[0m';\n }\n result += buildAnsiCode(cellStyle);\n }\n currentStyle = cellStyle;\n }\n\n result += char || ' ';\n if (char) _hasContent = true;\n }\n\n // Reset at end of line if we had styling\n if (!styleEquals(currentStyle, DEFAULT_STYLE)) {\n result += '\\x1b[0m';\n }\n\n // Trim leading whitespace - tools like ncu/npm use cursor positioning\n // which creates lines with leading spaces when interpreted by xterm\n lines.push(result.trimStart());\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":["xterm","Terminal","default","COLOR_MODE_DEFAULT","COLOR_MODE_16","COLOR_MODE_256","COLOR_MODE_RGB","DEFAULT_STYLE","fg","fgMode","bg","bgMode","bold","dim","italic","underline","inverse","strikethrough","styleEquals","a","b","buildAnsiCode","style","codes","push","r","g","length","join","TerminalBuffer","write","data","str","toString","terminal","resize","cols","rows","getLines","buffer","active","lines","i","bufferLine","getLine","result","currentStyle","_hasContent","lastContentIndex","j","cell","getCell","getChars","char","cellStyle","getFgColor","getFgColorMode","getBgColor","getBgColorMode","isBold","isDim","isItalic","isUnderline","isInverse","isStrikethrough","trimStart","pop","lineCount","dispose","scrollback","allowProposedApi"],"mappings":"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"}
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() - preserves whitespace\n const lines = [...this.allLines];\n\n // Trim trailing empty lines only\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 this.allLines = [];\n }\n}\n"],"names":["StreamingTerminal","TerminalBuffer","write","data","terminal","resize","_cols","getLines","hasContent","line","renderLine","reset","allLines","push","lines","length","pop","lineCount","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,sEAAsE;QACtE,MAAMK,QAAQ;eAAI,IAAI,CAACF,QAAQ;SAAC;QAEhC,iCAAiC;QACjC,MAAOE,MAAMC,MAAM,GAAG,KAAKD,KAAK,CAACA,MAAMC,MAAM,GAAG,EAAE,KAAK,GAAI;YACzDD,MAAME,GAAG;QACX;QAEA,OAAOF;IACT;IAEA;;GAEC,GACD,IAAIG,YAAoB;QACtB,OAAO,IAAI,CAACV,QAAQ,GAAGQ,MAAM;IAC/B;IAEA;;GAEC,GACDG,UAAgB;QACd,IAAI,CAACd,QAAQ,CAACc,OAAO;QACrB,IAAI,CAACN,QAAQ,GAAG,EAAE;IACpB;IArEA,YAAYN,KAAa,EAAEa,cAAc,KAAK,CAAE;aAFxCP,WAAqB,EAAE;QAG7B,6DAA6D;QAC7D,iCAAiC;QACjC,IAAI,CAACR,QAAQ,GAAG,IAAIJ;QAEpB,sDAAsD;QACtD,IAAI,CAACI,QAAQ,CAACgB,oBAAoB,CAAC;YACjC,MAAMX,OAAO,IAAI,CAACL,QAAQ,CAACM,UAAU;YACrC,IAAI,CAACN,QAAQ,CAACO,KAAK;YACnB,IAAI,CAACC,QAAQ,CAACC,IAAI,CAACJ;QACrB;IACF;AA2DF"}
@@ -1,6 +1,15 @@
1
+ /**
2
+ * Wrapper around terminal-model's StreamingTerminal that provides a virtual terminal buffer.
3
+ * Interprets ANSI escape sequences (cursor movement, line clearing, etc.) to produce
4
+ * the actual rendered output rather than raw intermediate states.
5
+ *
6
+ * This implementation preserves whitespace and blank lines by NOT calling trimStart(),
7
+ * which was the bug in the previous xterm-based implementation.
8
+ */
1
9
  export declare class TerminalBuffer {
2
10
  private terminal;
3
- constructor(cols: number, scrollback?: number);
11
+ private allLines;
12
+ constructor(_cols: number, _scrollback?: number);
4
13
  /**
5
14
  * Write raw data to the terminal buffer.
6
15
  * The terminal interprets all ANSI sequences automatically.
@@ -8,12 +17,16 @@ export declare class TerminalBuffer {
8
17
  write(data: string | Buffer): void;
9
18
  /**
10
19
  * Resize the terminal width.
20
+ * terminal-model doesn't use column constraints, so this is a no-op for compatibility.
11
21
  */
12
- resize(cols: number): void;
22
+ resize(_cols: number): void;
13
23
  /**
14
24
  * Extract the rendered lines from the terminal buffer.
15
25
  * This returns the actual visible content after all ANSI sequences
16
26
  * have been processed, with color codes preserved.
27
+ *
28
+ * CRITICAL: Unlike the xterm implementation, we do NOT call trimStart(),
29
+ * which preserves legitimate indentation and blank lines.
17
30
  */
18
31
  getLines(): string[];
19
32
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "spawn-term",
3
- "version": "3.4.2",
3
+ "version": "3.5.0",
4
4
  "description": "Formats spawn with for terminal grouping",
5
5
  "keywords": [
6
6
  "spawn",
@@ -42,11 +42,11 @@
42
42
  "version": "tsds version"
43
43
  },
44
44
  "dependencies": {
45
- "@xterm/headless": "^6.0.0",
46
45
  "cross-spawn-cb": "^3.0.0",
47
46
  "install-module-linked": "^1.3.16",
48
47
  "on-one": "^1.0.0",
49
- "queue-cb": "^1.0.0"
48
+ "queue-cb": "^1.0.0",
49
+ "terminal-model": "^0.1.0"
50
50
  },
51
51
  "devDependencies": {
52
52
  "@types/mocha": "*",