spawn-term 3.1.1 → 3.1.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.
@@ -0,0 +1,48 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ function _export(target, all) {
6
+ for(var name in all)Object.defineProperty(target, name, {
7
+ enumerable: true,
8
+ get: Object.getOwnPropertyDescriptor(all, name).get
9
+ });
10
+ }
11
+ _export(exports, {
12
+ get arrayFind () {
13
+ return arrayFind;
14
+ },
15
+ get stringEndsWith () {
16
+ return stringEndsWith;
17
+ }
18
+ });
19
+ /**
20
+ * Compatibility Layer for Node.js 0.8+
21
+ * Local to this package - contains only needed functions.
22
+ */ /**
23
+ * String.prototype.endsWith wrapper for Node.js 0.8+
24
+ * - Uses native endsWith on Node 4.0+ / ES2015+
25
+ * - Falls back to lastIndexOf on Node 0.8-3.x
26
+ */ var hasEndsWith = typeof String.prototype.endsWith === 'function';
27
+ function stringEndsWith(str, search, position) {
28
+ if (hasEndsWith) {
29
+ return str.endsWith(search, position);
30
+ }
31
+ var len = position === undefined ? str.length : position;
32
+ return str.lastIndexOf(search) === len - search.length;
33
+ }
34
+ /**
35
+ * Array.prototype.find wrapper for Node.js 0.8+
36
+ * - Uses native find on Node 4.0+ / ES2015+
37
+ * - Falls back to loop on Node 0.8-3.x
38
+ */ var hasArrayFind = typeof Array.prototype.find === 'function';
39
+ function arrayFind(arr, predicate) {
40
+ if (hasArrayFind) {
41
+ return arr.find(predicate);
42
+ }
43
+ for(var i = 0; i < arr.length; i++){
44
+ if (predicate(arr[i], i, arr)) return arr[i];
45
+ }
46
+ return undefined;
47
+ }
48
+ /* CJS INTEROP */ if (exports.__esModule && exports.default) { try { Object.defineProperty(exports.default, '__esModule', { value: true }); for (var key in exports) { exports.default[key] = exports[key]; } } catch (_) {}; module.exports = exports.default; }
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["/Users/kevin/Dev/OpenSource/node/spawn-term/src/compat.ts"],"sourcesContent":["/**\n * Compatibility Layer for Node.js 0.8+\n * Local to this package - contains only needed functions.\n */\n\n/**\n * String.prototype.endsWith wrapper for Node.js 0.8+\n * - Uses native endsWith on Node 4.0+ / ES2015+\n * - Falls back to lastIndexOf on Node 0.8-3.x\n */\nvar hasEndsWith = typeof String.prototype.endsWith === 'function';\n\nexport function stringEndsWith(str: string, search: string, position?: number): boolean {\n if (hasEndsWith) {\n return str.endsWith(search, position);\n }\n var len = position === undefined ? str.length : position;\n return str.lastIndexOf(search) === len - search.length;\n}\n\n/**\n * Array.prototype.find wrapper for Node.js 0.8+\n * - Uses native find on Node 4.0+ / ES2015+\n * - Falls back to loop on Node 0.8-3.x\n */\nvar hasArrayFind = typeof Array.prototype.find === 'function';\n\nexport function arrayFind<T>(arr: T[], predicate: (item: T, index: number, arr: T[]) => boolean): T | undefined {\n if (hasArrayFind) {\n return arr.find(predicate);\n }\n for (var i = 0; i < arr.length; i++) {\n if (predicate(arr[i], i, arr)) return arr[i];\n }\n return undefined;\n}\n"],"names":["arrayFind","stringEndsWith","hasEndsWith","String","prototype","endsWith","str","search","position","len","undefined","length","lastIndexOf","hasArrayFind","Array","find","arr","predicate","i"],"mappings":";;;;;;;;;;;QA2BgBA;eAAAA;;QAfAC;eAAAA;;;AAZhB;;;CAGC,GAED;;;;CAIC,GACD,IAAIC,cAAc,OAAOC,OAAOC,SAAS,CAACC,QAAQ,KAAK;AAEhD,SAASJ,eAAeK,GAAW,EAAEC,MAAc,EAAEC,QAAiB;IAC3E,IAAIN,aAAa;QACf,OAAOI,IAAID,QAAQ,CAACE,QAAQC;IAC9B;IACA,IAAIC,MAAMD,aAAaE,YAAYJ,IAAIK,MAAM,GAAGH;IAChD,OAAOF,IAAIM,WAAW,CAACL,YAAYE,MAAMF,OAAOI,MAAM;AACxD;AAEA;;;;CAIC,GACD,IAAIE,eAAe,OAAOC,MAAMV,SAAS,CAACW,IAAI,KAAK;AAE5C,SAASf,UAAagB,GAAQ,EAAEC,SAAwD;IAC7F,IAAIJ,cAAc;QAChB,OAAOG,IAAID,IAAI,CAACE;IAClB;IACA,IAAK,IAAIC,IAAI,GAAGA,IAAIF,IAAIL,MAAM,EAAEO,IAAK;QACnC,IAAID,UAAUD,GAAG,CAACE,EAAE,EAAEA,GAAGF,MAAM,OAAOA,GAAG,CAACE,EAAE;IAC9C;IACA,OAAOR;AACT"}
@@ -8,11 +8,12 @@ Object.defineProperty(exports, "calculateColumnWidth", {
8
8
  return calculateColumnWidth;
9
9
  }
10
10
  });
11
+ var _compatts = require("../compat.js");
11
12
  var _constantsts = require("../constants.js");
12
13
  function calculateColumnWidth(groupWidth, terminalWidth, maxGroupLength) {
13
14
  if (typeof groupWidth === 'number') return groupWidth;
14
15
  if (groupWidth === 'max') return Math.min(maxGroupLength, Math.floor(terminalWidth * _constantsts.MAX_COLUMN_WIDTH_PERCENT));
15
- if (typeof groupWidth === 'string' && groupWidth.endsWith('%')) {
16
+ if (typeof groupWidth === 'string' && (0, _compatts.stringEndsWith)(groupWidth, '%')) {
16
17
  var pct = parseInt(groupWidth, 10) / 100;
17
18
  return Math.floor(terminalWidth * pct);
18
19
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/OpenSource/node/spawn-term/src/lib/format.ts"],"sourcesContent":["import { FALLBACK_COLUMN_WIDTH, MAX_COLUMN_WIDTH_PERCENT } from '../constants.ts';\n\nexport type GroupWidth = number | `${number}%` | 'max';\n\nexport function calculateColumnWidth(groupWidth: GroupWidth, terminalWidth: number, maxGroupLength: number): number {\n if (typeof groupWidth === 'number') return groupWidth;\n if (groupWidth === 'max') return Math.min(maxGroupLength, Math.floor(terminalWidth * MAX_COLUMN_WIDTH_PERCENT));\n if (typeof groupWidth === 'string' && groupWidth.endsWith('%')) {\n const pct = parseInt(groupWidth, 10) / 100;\n return Math.floor(terminalWidth * pct);\n }\n return FALLBACK_COLUMN_WIDTH;\n}\n"],"names":["calculateColumnWidth","groupWidth","terminalWidth","maxGroupLength","Math","min","floor","MAX_COLUMN_WIDTH_PERCENT","endsWith","pct","parseInt","FALLBACK_COLUMN_WIDTH"],"mappings":";;;;+BAIgBA;;;eAAAA;;;2BAJgD;AAIzD,SAASA,qBAAqBC,UAAsB,EAAEC,aAAqB,EAAEC,cAAsB;IACxG,IAAI,OAAOF,eAAe,UAAU,OAAOA;IAC3C,IAAIA,eAAe,OAAO,OAAOG,KAAKC,GAAG,CAACF,gBAAgBC,KAAKE,KAAK,CAACJ,gBAAgBK,qCAAwB;IAC7G,IAAI,OAAON,eAAe,YAAYA,WAAWO,QAAQ,CAAC,MAAM;QAC9D,IAAMC,MAAMC,SAAST,YAAY,MAAM;QACvC,OAAOG,KAAKE,KAAK,CAACJ,gBAAgBO;IACpC;IACA,OAAOE,kCAAqB;AAC9B"}
1
+ {"version":3,"sources":["/Users/kevin/Dev/OpenSource/node/spawn-term/src/lib/format.ts"],"sourcesContent":["import { stringEndsWith } from '../compat.ts';\nimport { FALLBACK_COLUMN_WIDTH, MAX_COLUMN_WIDTH_PERCENT } from '../constants.ts';\n\nexport type GroupWidth = number | `${number}%` | 'max';\n\nexport function calculateColumnWidth(groupWidth: GroupWidth, terminalWidth: number, maxGroupLength: number): number {\n if (typeof groupWidth === 'number') return groupWidth;\n if (groupWidth === 'max') return Math.min(maxGroupLength, Math.floor(terminalWidth * MAX_COLUMN_WIDTH_PERCENT));\n if (typeof groupWidth === 'string' && stringEndsWith(groupWidth, '%')) {\n const pct = parseInt(groupWidth, 10) / 100;\n return Math.floor(terminalWidth * pct);\n }\n return FALLBACK_COLUMN_WIDTH;\n}\n"],"names":["calculateColumnWidth","groupWidth","terminalWidth","maxGroupLength","Math","min","floor","MAX_COLUMN_WIDTH_PERCENT","stringEndsWith","pct","parseInt","FALLBACK_COLUMN_WIDTH"],"mappings":";;;;+BAKgBA;;;eAAAA;;;wBALe;2BACiC;AAIzD,SAASA,qBAAqBC,UAAsB,EAAEC,aAAqB,EAAEC,cAAsB;IACxG,IAAI,OAAOF,eAAe,UAAU,OAAOA;IAC3C,IAAIA,eAAe,OAAO,OAAOG,KAAKC,GAAG,CAACF,gBAAgBC,KAAKE,KAAK,CAACJ,gBAAgBK,qCAAwB;IAC7G,IAAI,OAAON,eAAe,YAAYO,IAAAA,wBAAc,EAACP,YAAY,MAAM;QACrE,IAAMQ,MAAMC,SAAST,YAAY,MAAM;QACvC,OAAOG,KAAKE,KAAK,CAACJ,gBAAgBO;IACpC;IACA,OAAOE,kCAAqB;AAC9B"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Compatibility Layer for Node.js 0.8+
3
+ * Local to this package - contains only needed functions.
4
+ */
5
+ export declare function stringEndsWith(str: string, search: string, position?: number): boolean;
6
+ export declare function arrayFind<T>(arr: T[], predicate: (item: T, index: number, arr: T[]) => boolean): T | undefined;
@@ -8,6 +8,7 @@ Object.defineProperty(exports, "ProcessStore", {
8
8
  return ProcessStore;
9
9
  }
10
10
  });
11
+ var _compatts = require("../compat.js");
11
12
  var _constantsts = require("../constants.js");
12
13
  var _typests = require("../types.js");
13
14
  function _array_like_to_array(arr, len) {
@@ -108,7 +109,7 @@ var ProcessStore = /*#__PURE__*/ function() {
108
109
  this.getCompletedProcesses = function() {
109
110
  // Return in completion order
110
111
  return _this.completedIds.map(function(id) {
111
- return _this.processes.find(function(p) {
112
+ return (0, _compatts.arrayFind)(_this.processes, function(p) {
112
113
  return p.id === id;
113
114
  });
114
115
  }).filter(function(p) {
@@ -208,7 +209,7 @@ var ProcessStore = /*#__PURE__*/ function() {
208
209
  this.notify();
209
210
  };
210
211
  _proto.updateProcess = function updateProcess(id, update) {
211
- var oldProcess = this.processes.find(function(p) {
212
+ var oldProcess = (0, _compatts.arrayFind)(this.processes, function(p) {
212
213
  return p.id === id;
213
214
  });
214
215
  var wasRunning = (oldProcess === null || oldProcess === void 0 ? void 0 : oldProcess.state) === 'running';
@@ -229,7 +230,7 @@ var ProcessStore = /*#__PURE__*/ function() {
229
230
  this.notify();
230
231
  };
231
232
  _proto.appendLines = function appendLines(id, newLines) {
232
- var process = this.processes.find(function(p) {
233
+ var process = (0, _compatts.arrayFind)(this.processes, function(p) {
233
234
  return p.id === id;
234
235
  });
235
236
  if (process) {
@@ -239,7 +240,7 @@ var ProcessStore = /*#__PURE__*/ function() {
239
240
  }
240
241
  };
241
242
  _proto.getProcess = function getProcess(id) {
242
- return this.processes.find(function(p) {
243
+ return (0, _compatts.arrayFind)(this.processes, function(p) {
243
244
  return p.id === id;
244
245
  });
245
246
  };
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/OpenSource/node/spawn-term/src/state/processStore.ts"],"sourcesContent":["import { DEFAULT_COLUMN_WIDTH } from '../constants.ts';\nimport type { ChildProcess, Line, SessionOptions } from '../types.ts';\nimport { LineType } from '../types.ts';\n\ntype Listener = () => void;\ntype Mode = 'normal' | 'interactive';\n\nexport class ProcessStore {\n private processes: ChildProcess[] = [];\n private completedIds: string[] = []; // Track completion order\n private listeners = new Set<Listener>();\n private shouldExit = false;\n private exitCallback: (() => void) | null = null;\n\n // UI state\n private mode: Mode = 'normal';\n private selectedIndex = 0;\n private expandedId: string | null = null;\n private scrollOffset = 0;\n private listScrollOffset = 0; // Viewport offset for process list\n private errorFooterExpanded = false; // For non-interactive error footer\n private bufferVersion = 0; // Increments on every notify() to trigger re-renders\n\n // Session-level display settings (set once at session creation)\n private header: string | undefined;\n private showStatusBar = false;\n private isInteractive = false;\n\n constructor(options: SessionOptions = {}) {\n this.header = options.header;\n this.showStatusBar = options.showStatusBar ?? false;\n this.isInteractive = options.interactive ?? false;\n }\n\n // useSyncExternalStore API\n subscribe = (listener: Listener): (() => void) => {\n this.listeners.add(listener);\n return () => this.listeners.delete(listener);\n };\n\n getSnapshot = (): ChildProcess[] => this.processes;\n\n // Filtered getters\n getRunningProcesses = (): ChildProcess[] => {\n return this.processes.filter((p) => p.state === 'running');\n };\n\n getCompletedProcesses = (): ChildProcess[] => {\n // Return in completion order\n return this.completedIds.map((id) => this.processes.find((p) => p.id === id)).filter((p): p is ChildProcess => p !== undefined);\n };\n\n getFailedProcesses = (): ChildProcess[] => {\n return this.processes.filter((p) => p.state === 'error');\n };\n\n // Counts\n getRunningCount = (): number => this.processes.filter((p) => p.state === 'running').length;\n getMaxGroupLength = (): number => {\n if (this.processes.length === 0) return DEFAULT_COLUMN_WIDTH;\n return Math.max(...this.processes.map((p) => (p.group || p.title).length));\n };\n getDoneCount = (): number => this.processes.filter((p) => p.state !== 'running').length;\n getErrorCount = (): number => this.processes.filter((p) => p.state === 'error').length;\n getErrorLineCount = (): number => {\n return this.processes.filter((p) => p.state === 'error').reduce((total, p) => total + this.getProcessLineCount(p.id), 0);\n };\n\n // UI state getters\n getMode = (): Mode => this.mode;\n getSelectedIndex = (): number => this.selectedIndex;\n getExpandedId = (): string | null => this.expandedId;\n getScrollOffset = (): number => this.scrollOffset;\n getListScrollOffset = (): number => this.listScrollOffset;\n getErrorFooterExpanded = (): boolean => this.errorFooterExpanded;\n getBufferVersion = (): number => this.bufferVersion;\n // Session-level getters (set at session creation, immutable)\n getHeader = (): string | undefined => this.header;\n getShowStatusBar = (): boolean => this.showStatusBar;\n getIsInteractive = (): boolean => this.isInteractive;\n isAllComplete = (): boolean => this.processes.length > 0 && this.processes.every((p) => p.state !== 'running');\n\n // Mutations - Ink handles render throttling at 30 FPS\n addProcess(process: ChildProcess): void {\n this.processes = [...this.processes, process];\n this.notify();\n }\n\n updateProcess(id: string, update: Partial<ChildProcess>): void {\n const oldProcess = this.processes.find((p) => p.id === id);\n const wasRunning = oldProcess?.state === 'running';\n const isNowComplete = update.state && update.state !== 'running';\n\n this.processes = this.processes.map((p) => (p.id === id ? { ...p, ...update } : p));\n\n // Track completion order\n if (wasRunning && isNowComplete && !this.completedIds.includes(id)) {\n this.completedIds = [...this.completedIds, id];\n }\n\n // Auto-expand error footer when all complete with errors (non-interactive only)\n if (!this.isInteractive && this.isAllComplete() && this.getErrorCount() > 0) {\n this.errorFooterExpanded = true;\n }\n\n this.notify();\n }\n\n appendLines(id: string, newLines: Line[]): void {\n const process = this.processes.find((p) => p.id === id);\n if (process) {\n this.updateProcess(id, { lines: process.lines.concat(newLines) });\n }\n }\n\n getProcess(id: string): ChildProcess | undefined {\n return this.processes.find((p) => p.id === id);\n }\n\n // Get rendered lines from terminal buffer or fallback to lines array\n getProcessLines(id: string): Line[] {\n const process = this.getProcess(id);\n if (!process) return [];\n if (process.terminalBuffer) {\n return process.terminalBuffer.getLines().map((text) => ({\n type: LineType.stdout,\n text,\n }));\n }\n return process.lines;\n }\n\n // Get line count from terminal buffer or lines array\n getProcessLineCount(id: string): number {\n const process = this.getProcess(id);\n if (!process) return 0;\n if (process.terminalBuffer) {\n return process.terminalBuffer.lineCount;\n }\n return process.lines.length;\n }\n\n // UI state mutations\n setMode(mode: Mode): void {\n this.mode = mode;\n if (mode === 'interactive') {\n this.selectedIndex = 0;\n }\n this.notify();\n }\n\n // Interactive mode navigation\n selectNext(visibleCount?: number): void {\n if (this.processes.length > 0) {\n this.selectedIndex = (this.selectedIndex + 1) % this.processes.length;\n this.adjustListScroll(visibleCount);\n this.notify();\n }\n }\n\n selectPrev(visibleCount?: number): void {\n if (this.processes.length > 0) {\n this.selectedIndex = (this.selectedIndex - 1 + this.processes.length) % this.processes.length;\n this.adjustListScroll(visibleCount);\n this.notify();\n }\n }\n\n private adjustListScroll(visibleCount?: number): void {\n if (!visibleCount || visibleCount <= 0) return;\n\n // Ensure selected item is visible in viewport\n if (this.selectedIndex < this.listScrollOffset) {\n // Selected is above viewport - scroll up\n this.listScrollOffset = this.selectedIndex;\n } else if (this.selectedIndex >= this.listScrollOffset + visibleCount) {\n // Selected is below viewport - scroll down\n this.listScrollOffset = this.selectedIndex - visibleCount + 1;\n }\n }\n\n getSelectedProcess(): ChildProcess | undefined {\n return this.processes[this.selectedIndex];\n }\n\n // Error footer methods (for non-interactive mode)\n toggleErrorFooter(): void {\n this.errorFooterExpanded = !this.errorFooterExpanded;\n this.notify();\n }\n\n expandErrorFooter(): void {\n if (!this.errorFooterExpanded) {\n this.errorFooterExpanded = true;\n this.notify();\n }\n }\n\n getErrorLines(): Array<{ processName: string; lines: Line[] }> {\n return this.getFailedProcesses().map((p) => ({\n processName: p.group || p.title,\n lines: this.getProcessLines(p.id),\n }));\n }\n\n // Expansion methods\n toggleExpand(): void {\n const selected = this.getSelectedProcess();\n if (!selected) return;\n\n if (this.expandedId === selected.id) {\n // Collapse\n this.expandedId = null;\n this.scrollOffset = 0;\n } else {\n // Expand\n this.expandedId = selected.id;\n this.scrollOffset = 0;\n }\n this.notify();\n }\n\n collapse(): void {\n this.expandedId = null;\n this.scrollOffset = 0;\n this.notify();\n }\n\n scrollDown(maxVisible: number): void {\n if (!this.expandedId) return;\n const lineCount = this.getProcessLineCount(this.expandedId);\n if (lineCount === 0) return;\n\n const maxOffset = Math.max(0, lineCount - maxVisible);\n if (this.scrollOffset < maxOffset) {\n this.scrollOffset++;\n this.notify();\n }\n }\n\n scrollUp(): void {\n if (!this.expandedId) return;\n if (this.scrollOffset > 0) {\n this.scrollOffset--;\n this.notify();\n }\n }\n\n // Page scrolling (scroll by maxVisible lines at once)\n scrollPageDown(maxVisible: number): void {\n if (!this.expandedId) return;\n const lineCount = this.getProcessLineCount(this.expandedId);\n if (lineCount === 0) return;\n\n const maxOffset = Math.max(0, lineCount - maxVisible);\n this.scrollOffset = Math.min(this.scrollOffset + maxVisible, maxOffset);\n this.notify();\n }\n\n scrollPageUp(maxVisible: number): void {\n if (!this.expandedId) return;\n this.scrollOffset = Math.max(0, this.scrollOffset - maxVisible);\n this.notify();\n }\n\n // Jump to top/bottom\n scrollToTop(): void {\n if (!this.expandedId) return;\n this.scrollOffset = 0;\n this.notify();\n }\n\n scrollToBottom(maxVisible: number): void {\n if (!this.expandedId) return;\n const lineCount = this.getProcessLineCount(this.expandedId);\n if (lineCount === 0) return;\n\n this.scrollOffset = Math.max(0, lineCount - maxVisible);\n this.notify();\n }\n\n // Exit signaling\n signalExit(callback: () => void): void {\n this.shouldExit = true;\n this.exitCallback = callback;\n this.notify();\n }\n\n getShouldExit = (): boolean => this.shouldExit;\n getExitCallback = (): (() => void) | null => this.exitCallback;\n\n reset(): void {\n // Dispose terminal buffers before clearing\n for (const process of this.processes) {\n process.terminalBuffer?.dispose();\n }\n this.processes = [];\n this.completedIds = [];\n this.shouldExit = false;\n this.exitCallback = null;\n this.mode = 'normal';\n this.selectedIndex = 0;\n this.expandedId = null;\n this.scrollOffset = 0;\n this.listScrollOffset = 0;\n this.errorFooterExpanded = false;\n this.header = undefined;\n }\n\n // Public notify for session to trigger updates when terminal buffer changes\n notify(): void {\n this.bufferVersion++;\n this.listeners.forEach((l) => {\n l();\n });\n }\n}\n\n// Note: No global singleton - session creates its own store instance\n"],"names":["ProcessStore","options","processes","completedIds","listeners","Set","shouldExit","exitCallback","mode","selectedIndex","expandedId","scrollOffset","listScrollOffset","errorFooterExpanded","bufferVersion","showStatusBar","isInteractive","subscribe","listener","add","delete","getSnapshot","getRunningProcesses","filter","p","state","getCompletedProcesses","map","id","find","undefined","getFailedProcesses","getRunningCount","length","getMaxGroupLength","Math","DEFAULT_COLUMN_WIDTH","max","group","title","getDoneCount","getErrorCount","getErrorLineCount","reduce","total","getProcessLineCount","getMode","getSelectedIndex","getExpandedId","getScrollOffset","getListScrollOffset","getErrorFooterExpanded","getBufferVersion","getHeader","header","getShowStatusBar","getIsInteractive","isAllComplete","every","getShouldExit","getExitCallback","interactive","addProcess","process","notify","updateProcess","update","oldProcess","wasRunning","isNowComplete","includes","appendLines","newLines","lines","concat","getProcess","getProcessLines","terminalBuffer","getLines","text","type","LineType","stdout","lineCount","setMode","selectNext","visibleCount","adjustListScroll","selectPrev","getSelectedProcess","toggleErrorFooter","expandErrorFooter","getErrorLines","processName","toggleExpand","selected","collapse","scrollDown","maxVisible","maxOffset","scrollUp","scrollPageDown","min","scrollPageUp","scrollToTop","scrollToBottom","signalExit","callback","reset","dispose","forEach","l"],"mappings":"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"}
1
+ {"version":3,"sources":["/Users/kevin/Dev/OpenSource/node/spawn-term/src/state/processStore.ts"],"sourcesContent":["import { arrayFind } from '../compat.ts';\nimport { DEFAULT_COLUMN_WIDTH } from '../constants.ts';\nimport type { ChildProcess, Line, SessionOptions } from '../types.ts';\nimport { LineType } from '../types.ts';\n\ntype Listener = () => void;\ntype Mode = 'normal' | 'interactive';\n\nexport class ProcessStore {\n private processes: ChildProcess[] = [];\n private completedIds: string[] = []; // Track completion order\n private listeners = new Set<Listener>();\n private shouldExit = false;\n private exitCallback: (() => void) | null = null;\n\n // UI state\n private mode: Mode = 'normal';\n private selectedIndex = 0;\n private expandedId: string | null = null;\n private scrollOffset = 0;\n private listScrollOffset = 0; // Viewport offset for process list\n private errorFooterExpanded = false; // For non-interactive error footer\n private bufferVersion = 0; // Increments on every notify() to trigger re-renders\n\n // Session-level display settings (set once at session creation)\n private header: string | undefined;\n private showStatusBar = false;\n private isInteractive = false;\n\n constructor(options: SessionOptions = {}) {\n this.header = options.header;\n this.showStatusBar = options.showStatusBar ?? false;\n this.isInteractive = options.interactive ?? false;\n }\n\n // useSyncExternalStore API\n subscribe = (listener: Listener): (() => void) => {\n this.listeners.add(listener);\n return () => this.listeners.delete(listener);\n };\n\n getSnapshot = (): ChildProcess[] => this.processes;\n\n // Filtered getters\n getRunningProcesses = (): ChildProcess[] => {\n return this.processes.filter((p) => p.state === 'running');\n };\n\n getCompletedProcesses = (): ChildProcess[] => {\n // Return in completion order\n return this.completedIds.map((id) => arrayFind(this.processes, (p) => p.id === id)).filter((p): p is ChildProcess => p !== undefined);\n };\n\n getFailedProcesses = (): ChildProcess[] => {\n return this.processes.filter((p) => p.state === 'error');\n };\n\n // Counts\n getRunningCount = (): number => this.processes.filter((p) => p.state === 'running').length;\n getMaxGroupLength = (): number => {\n if (this.processes.length === 0) return DEFAULT_COLUMN_WIDTH;\n return Math.max(...this.processes.map((p) => (p.group || p.title).length));\n };\n getDoneCount = (): number => this.processes.filter((p) => p.state !== 'running').length;\n getErrorCount = (): number => this.processes.filter((p) => p.state === 'error').length;\n getErrorLineCount = (): number => {\n return this.processes.filter((p) => p.state === 'error').reduce((total, p) => total + this.getProcessLineCount(p.id), 0);\n };\n\n // UI state getters\n getMode = (): Mode => this.mode;\n getSelectedIndex = (): number => this.selectedIndex;\n getExpandedId = (): string | null => this.expandedId;\n getScrollOffset = (): number => this.scrollOffset;\n getListScrollOffset = (): number => this.listScrollOffset;\n getErrorFooterExpanded = (): boolean => this.errorFooterExpanded;\n getBufferVersion = (): number => this.bufferVersion;\n // Session-level getters (set at session creation, immutable)\n getHeader = (): string | undefined => this.header;\n getShowStatusBar = (): boolean => this.showStatusBar;\n getIsInteractive = (): boolean => this.isInteractive;\n isAllComplete = (): boolean => this.processes.length > 0 && this.processes.every((p) => p.state !== 'running');\n\n // Mutations - Ink handles render throttling at 30 FPS\n addProcess(process: ChildProcess): void {\n this.processes = [...this.processes, process];\n this.notify();\n }\n\n updateProcess(id: string, update: Partial<ChildProcess>): void {\n const oldProcess = arrayFind(this.processes, (p) => p.id === id);\n const wasRunning = oldProcess?.state === 'running';\n const isNowComplete = update.state && update.state !== 'running';\n\n this.processes = this.processes.map((p) => (p.id === id ? { ...p, ...update } : p));\n\n // Track completion order\n if (wasRunning && isNowComplete && !this.completedIds.includes(id)) {\n this.completedIds = [...this.completedIds, id];\n }\n\n // Auto-expand error footer when all complete with errors (non-interactive only)\n if (!this.isInteractive && this.isAllComplete() && this.getErrorCount() > 0) {\n this.errorFooterExpanded = true;\n }\n\n this.notify();\n }\n\n appendLines(id: string, newLines: Line[]): void {\n const process = arrayFind(this.processes, (p) => p.id === id);\n if (process) {\n this.updateProcess(id, { lines: process.lines.concat(newLines) });\n }\n }\n\n getProcess(id: string): ChildProcess | undefined {\n return arrayFind(this.processes, (p) => p.id === id);\n }\n\n // Get rendered lines from terminal buffer or fallback to lines array\n getProcessLines(id: string): Line[] {\n const process = this.getProcess(id);\n if (!process) return [];\n if (process.terminalBuffer) {\n return process.terminalBuffer.getLines().map((text) => ({\n type: LineType.stdout,\n text,\n }));\n }\n return process.lines;\n }\n\n // Get line count from terminal buffer or lines array\n getProcessLineCount(id: string): number {\n const process = this.getProcess(id);\n if (!process) return 0;\n if (process.terminalBuffer) {\n return process.terminalBuffer.lineCount;\n }\n return process.lines.length;\n }\n\n // UI state mutations\n setMode(mode: Mode): void {\n this.mode = mode;\n if (mode === 'interactive') {\n this.selectedIndex = 0;\n }\n this.notify();\n }\n\n // Interactive mode navigation\n selectNext(visibleCount?: number): void {\n if (this.processes.length > 0) {\n this.selectedIndex = (this.selectedIndex + 1) % this.processes.length;\n this.adjustListScroll(visibleCount);\n this.notify();\n }\n }\n\n selectPrev(visibleCount?: number): void {\n if (this.processes.length > 0) {\n this.selectedIndex = (this.selectedIndex - 1 + this.processes.length) % this.processes.length;\n this.adjustListScroll(visibleCount);\n this.notify();\n }\n }\n\n private adjustListScroll(visibleCount?: number): void {\n if (!visibleCount || visibleCount <= 0) return;\n\n // Ensure selected item is visible in viewport\n if (this.selectedIndex < this.listScrollOffset) {\n // Selected is above viewport - scroll up\n this.listScrollOffset = this.selectedIndex;\n } else if (this.selectedIndex >= this.listScrollOffset + visibleCount) {\n // Selected is below viewport - scroll down\n this.listScrollOffset = this.selectedIndex - visibleCount + 1;\n }\n }\n\n getSelectedProcess(): ChildProcess | undefined {\n return this.processes[this.selectedIndex];\n }\n\n // Error footer methods (for non-interactive mode)\n toggleErrorFooter(): void {\n this.errorFooterExpanded = !this.errorFooterExpanded;\n this.notify();\n }\n\n expandErrorFooter(): void {\n if (!this.errorFooterExpanded) {\n this.errorFooterExpanded = true;\n this.notify();\n }\n }\n\n getErrorLines(): Array<{ processName: string; lines: Line[] }> {\n return this.getFailedProcesses().map((p) => ({\n processName: p.group || p.title,\n lines: this.getProcessLines(p.id),\n }));\n }\n\n // Expansion methods\n toggleExpand(): void {\n const selected = this.getSelectedProcess();\n if (!selected) return;\n\n if (this.expandedId === selected.id) {\n // Collapse\n this.expandedId = null;\n this.scrollOffset = 0;\n } else {\n // Expand\n this.expandedId = selected.id;\n this.scrollOffset = 0;\n }\n this.notify();\n }\n\n collapse(): void {\n this.expandedId = null;\n this.scrollOffset = 0;\n this.notify();\n }\n\n scrollDown(maxVisible: number): void {\n if (!this.expandedId) return;\n const lineCount = this.getProcessLineCount(this.expandedId);\n if (lineCount === 0) return;\n\n const maxOffset = Math.max(0, lineCount - maxVisible);\n if (this.scrollOffset < maxOffset) {\n this.scrollOffset++;\n this.notify();\n }\n }\n\n scrollUp(): void {\n if (!this.expandedId) return;\n if (this.scrollOffset > 0) {\n this.scrollOffset--;\n this.notify();\n }\n }\n\n // Page scrolling (scroll by maxVisible lines at once)\n scrollPageDown(maxVisible: number): void {\n if (!this.expandedId) return;\n const lineCount = this.getProcessLineCount(this.expandedId);\n if (lineCount === 0) return;\n\n const maxOffset = Math.max(0, lineCount - maxVisible);\n this.scrollOffset = Math.min(this.scrollOffset + maxVisible, maxOffset);\n this.notify();\n }\n\n scrollPageUp(maxVisible: number): void {\n if (!this.expandedId) return;\n this.scrollOffset = Math.max(0, this.scrollOffset - maxVisible);\n this.notify();\n }\n\n // Jump to top/bottom\n scrollToTop(): void {\n if (!this.expandedId) return;\n this.scrollOffset = 0;\n this.notify();\n }\n\n scrollToBottom(maxVisible: number): void {\n if (!this.expandedId) return;\n const lineCount = this.getProcessLineCount(this.expandedId);\n if (lineCount === 0) return;\n\n this.scrollOffset = Math.max(0, lineCount - maxVisible);\n this.notify();\n }\n\n // Exit signaling\n signalExit(callback: () => void): void {\n this.shouldExit = true;\n this.exitCallback = callback;\n this.notify();\n }\n\n getShouldExit = (): boolean => this.shouldExit;\n getExitCallback = (): (() => void) | null => this.exitCallback;\n\n reset(): void {\n // Dispose terminal buffers before clearing\n for (const process of this.processes) {\n process.terminalBuffer?.dispose();\n }\n this.processes = [];\n this.completedIds = [];\n this.shouldExit = false;\n this.exitCallback = null;\n this.mode = 'normal';\n this.selectedIndex = 0;\n this.expandedId = null;\n this.scrollOffset = 0;\n this.listScrollOffset = 0;\n this.errorFooterExpanded = false;\n this.header = undefined;\n }\n\n // Public notify for session to trigger updates when terminal buffer changes\n notify(): void {\n this.bufferVersion++;\n this.listeners.forEach((l) => {\n l();\n });\n }\n}\n\n// Note: No global singleton - session creates its own store instance\n"],"names":["ProcessStore","options","processes","completedIds","listeners","Set","shouldExit","exitCallback","mode","selectedIndex","expandedId","scrollOffset","listScrollOffset","errorFooterExpanded","bufferVersion","showStatusBar","isInteractive","subscribe","listener","add","delete","getSnapshot","getRunningProcesses","filter","p","state","getCompletedProcesses","map","id","arrayFind","undefined","getFailedProcesses","getRunningCount","length","getMaxGroupLength","Math","DEFAULT_COLUMN_WIDTH","max","group","title","getDoneCount","getErrorCount","getErrorLineCount","reduce","total","getProcessLineCount","getMode","getSelectedIndex","getExpandedId","getScrollOffset","getListScrollOffset","getErrorFooterExpanded","getBufferVersion","getHeader","header","getShowStatusBar","getIsInteractive","isAllComplete","every","getShouldExit","getExitCallback","interactive","addProcess","process","notify","updateProcess","update","oldProcess","wasRunning","isNowComplete","includes","appendLines","newLines","lines","concat","getProcess","getProcessLines","terminalBuffer","getLines","text","type","LineType","stdout","lineCount","setMode","selectNext","visibleCount","adjustListScroll","selectPrev","getSelectedProcess","toggleErrorFooter","expandErrorFooter","getErrorLines","processName","toggleExpand","selected","collapse","scrollDown","maxVisible","maxOffset","scrollUp","scrollPageDown","min","scrollPageUp","scrollToTop","scrollToBottom","signalExit","callback","reset","dispose","forEach","l"],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Compatibility Layer for Node.js 0.8+
3
+ * Local to this package - contains only needed functions.
4
+ */ /**
5
+ * String.prototype.endsWith wrapper for Node.js 0.8+
6
+ * - Uses native endsWith on Node 4.0+ / ES2015+
7
+ * - Falls back to lastIndexOf on Node 0.8-3.x
8
+ */ var hasEndsWith = typeof String.prototype.endsWith === 'function';
9
+ export function stringEndsWith(str, search, position) {
10
+ if (hasEndsWith) {
11
+ return str.endsWith(search, position);
12
+ }
13
+ var len = position === undefined ? str.length : position;
14
+ return str.lastIndexOf(search) === len - search.length;
15
+ }
16
+ /**
17
+ * Array.prototype.find wrapper for Node.js 0.8+
18
+ * - Uses native find on Node 4.0+ / ES2015+
19
+ * - Falls back to loop on Node 0.8-3.x
20
+ */ var hasArrayFind = typeof Array.prototype.find === 'function';
21
+ export function arrayFind(arr, predicate) {
22
+ if (hasArrayFind) {
23
+ return arr.find(predicate);
24
+ }
25
+ for(var i = 0; i < arr.length; i++){
26
+ if (predicate(arr[i], i, arr)) return arr[i];
27
+ }
28
+ return undefined;
29
+ }
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["/Users/kevin/Dev/OpenSource/node/spawn-term/src/compat.ts"],"sourcesContent":["/**\n * Compatibility Layer for Node.js 0.8+\n * Local to this package - contains only needed functions.\n */\n\n/**\n * String.prototype.endsWith wrapper for Node.js 0.8+\n * - Uses native endsWith on Node 4.0+ / ES2015+\n * - Falls back to lastIndexOf on Node 0.8-3.x\n */\nvar hasEndsWith = typeof String.prototype.endsWith === 'function';\n\nexport function stringEndsWith(str: string, search: string, position?: number): boolean {\n if (hasEndsWith) {\n return str.endsWith(search, position);\n }\n var len = position === undefined ? str.length : position;\n return str.lastIndexOf(search) === len - search.length;\n}\n\n/**\n * Array.prototype.find wrapper for Node.js 0.8+\n * - Uses native find on Node 4.0+ / ES2015+\n * - Falls back to loop on Node 0.8-3.x\n */\nvar hasArrayFind = typeof Array.prototype.find === 'function';\n\nexport function arrayFind<T>(arr: T[], predicate: (item: T, index: number, arr: T[]) => boolean): T | undefined {\n if (hasArrayFind) {\n return arr.find(predicate);\n }\n for (var i = 0; i < arr.length; i++) {\n if (predicate(arr[i], i, arr)) return arr[i];\n }\n return undefined;\n}\n"],"names":["hasEndsWith","String","prototype","endsWith","stringEndsWith","str","search","position","len","undefined","length","lastIndexOf","hasArrayFind","Array","find","arrayFind","arr","predicate","i"],"mappings":"AAAA;;;CAGC,GAED;;;;CAIC,GACD,IAAIA,cAAc,OAAOC,OAAOC,SAAS,CAACC,QAAQ,KAAK;AAEvD,OAAO,SAASC,eAAeC,GAAW,EAAEC,MAAc,EAAEC,QAAiB;IAC3E,IAAIP,aAAa;QACf,OAAOK,IAAIF,QAAQ,CAACG,QAAQC;IAC9B;IACA,IAAIC,MAAMD,aAAaE,YAAYJ,IAAIK,MAAM,GAAGH;IAChD,OAAOF,IAAIM,WAAW,CAACL,YAAYE,MAAMF,OAAOI,MAAM;AACxD;AAEA;;;;CAIC,GACD,IAAIE,eAAe,OAAOC,MAAMX,SAAS,CAACY,IAAI,KAAK;AAEnD,OAAO,SAASC,UAAaC,GAAQ,EAAEC,SAAwD;IAC7F,IAAIL,cAAc;QAChB,OAAOI,IAAIF,IAAI,CAACG;IAClB;IACA,IAAK,IAAIC,IAAI,GAAGA,IAAIF,IAAIN,MAAM,EAAEQ,IAAK;QACnC,IAAID,UAAUD,GAAG,CAACE,EAAE,EAAEA,GAAGF,MAAM,OAAOA,GAAG,CAACE,EAAE;IAC9C;IACA,OAAOT;AACT"}
@@ -1,8 +1,9 @@
1
+ import { stringEndsWith } from '../compat.js';
1
2
  import { FALLBACK_COLUMN_WIDTH, MAX_COLUMN_WIDTH_PERCENT } from '../constants.js';
2
3
  export function calculateColumnWidth(groupWidth, terminalWidth, maxGroupLength) {
3
4
  if (typeof groupWidth === 'number') return groupWidth;
4
5
  if (groupWidth === 'max') return Math.min(maxGroupLength, Math.floor(terminalWidth * MAX_COLUMN_WIDTH_PERCENT));
5
- if (typeof groupWidth === 'string' && groupWidth.endsWith('%')) {
6
+ if (typeof groupWidth === 'string' && stringEndsWith(groupWidth, '%')) {
6
7
  const pct = parseInt(groupWidth, 10) / 100;
7
8
  return Math.floor(terminalWidth * pct);
8
9
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/OpenSource/node/spawn-term/src/lib/format.ts"],"sourcesContent":["import { FALLBACK_COLUMN_WIDTH, MAX_COLUMN_WIDTH_PERCENT } from '../constants.ts';\n\nexport type GroupWidth = number | `${number}%` | 'max';\n\nexport function calculateColumnWidth(groupWidth: GroupWidth, terminalWidth: number, maxGroupLength: number): number {\n if (typeof groupWidth === 'number') return groupWidth;\n if (groupWidth === 'max') return Math.min(maxGroupLength, Math.floor(terminalWidth * MAX_COLUMN_WIDTH_PERCENT));\n if (typeof groupWidth === 'string' && groupWidth.endsWith('%')) {\n const pct = parseInt(groupWidth, 10) / 100;\n return Math.floor(terminalWidth * pct);\n }\n return FALLBACK_COLUMN_WIDTH;\n}\n"],"names":["FALLBACK_COLUMN_WIDTH","MAX_COLUMN_WIDTH_PERCENT","calculateColumnWidth","groupWidth","terminalWidth","maxGroupLength","Math","min","floor","endsWith","pct","parseInt"],"mappings":"AAAA,SAASA,qBAAqB,EAAEC,wBAAwB,QAAQ,kBAAkB;AAIlF,OAAO,SAASC,qBAAqBC,UAAsB,EAAEC,aAAqB,EAAEC,cAAsB;IACxG,IAAI,OAAOF,eAAe,UAAU,OAAOA;IAC3C,IAAIA,eAAe,OAAO,OAAOG,KAAKC,GAAG,CAACF,gBAAgBC,KAAKE,KAAK,CAACJ,gBAAgBH;IACrF,IAAI,OAAOE,eAAe,YAAYA,WAAWM,QAAQ,CAAC,MAAM;QAC9D,MAAMC,MAAMC,SAASR,YAAY,MAAM;QACvC,OAAOG,KAAKE,KAAK,CAACJ,gBAAgBM;IACpC;IACA,OAAOV;AACT"}
1
+ {"version":3,"sources":["/Users/kevin/Dev/OpenSource/node/spawn-term/src/lib/format.ts"],"sourcesContent":["import { stringEndsWith } from '../compat.ts';\nimport { FALLBACK_COLUMN_WIDTH, MAX_COLUMN_WIDTH_PERCENT } from '../constants.ts';\n\nexport type GroupWidth = number | `${number}%` | 'max';\n\nexport function calculateColumnWidth(groupWidth: GroupWidth, terminalWidth: number, maxGroupLength: number): number {\n if (typeof groupWidth === 'number') return groupWidth;\n if (groupWidth === 'max') return Math.min(maxGroupLength, Math.floor(terminalWidth * MAX_COLUMN_WIDTH_PERCENT));\n if (typeof groupWidth === 'string' && stringEndsWith(groupWidth, '%')) {\n const pct = parseInt(groupWidth, 10) / 100;\n return Math.floor(terminalWidth * pct);\n }\n return FALLBACK_COLUMN_WIDTH;\n}\n"],"names":["stringEndsWith","FALLBACK_COLUMN_WIDTH","MAX_COLUMN_WIDTH_PERCENT","calculateColumnWidth","groupWidth","terminalWidth","maxGroupLength","Math","min","floor","pct","parseInt"],"mappings":"AAAA,SAASA,cAAc,QAAQ,eAAe;AAC9C,SAASC,qBAAqB,EAAEC,wBAAwB,QAAQ,kBAAkB;AAIlF,OAAO,SAASC,qBAAqBC,UAAsB,EAAEC,aAAqB,EAAEC,cAAsB;IACxG,IAAI,OAAOF,eAAe,UAAU,OAAOA;IAC3C,IAAIA,eAAe,OAAO,OAAOG,KAAKC,GAAG,CAACF,gBAAgBC,KAAKE,KAAK,CAACJ,gBAAgBH;IACrF,IAAI,OAAOE,eAAe,YAAYJ,eAAeI,YAAY,MAAM;QACrE,MAAMM,MAAMC,SAASP,YAAY,MAAM;QACvC,OAAOG,KAAKE,KAAK,CAACJ,gBAAgBK;IACpC;IACA,OAAOT;AACT"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Compatibility Layer for Node.js 0.8+
3
+ * Local to this package - contains only needed functions.
4
+ */
5
+ export declare function stringEndsWith(str: string, search: string, position?: number): boolean;
6
+ export declare function arrayFind<T>(arr: T[], predicate: (item: T, index: number, arr: T[]) => boolean): T | undefined;
@@ -1,3 +1,4 @@
1
+ import { arrayFind } from '../compat.js';
1
2
  import { DEFAULT_COLUMN_WIDTH } from '../constants.js';
2
3
  import { LineType } from '../types.js';
3
4
  export class ProcessStore {
@@ -10,7 +11,7 @@ export class ProcessStore {
10
11
  this.notify();
11
12
  }
12
13
  updateProcess(id, update) {
13
- const oldProcess = this.processes.find((p)=>p.id === id);
14
+ const oldProcess = arrayFind(this.processes, (p)=>p.id === id);
14
15
  const wasRunning = (oldProcess === null || oldProcess === void 0 ? void 0 : oldProcess.state) === 'running';
15
16
  const isNowComplete = update.state && update.state !== 'running';
16
17
  this.processes = this.processes.map((p)=>p.id === id ? {
@@ -31,7 +32,7 @@ export class ProcessStore {
31
32
  this.notify();
32
33
  }
33
34
  appendLines(id, newLines) {
34
- const process = this.processes.find((p)=>p.id === id);
35
+ const process = arrayFind(this.processes, (p)=>p.id === id);
35
36
  if (process) {
36
37
  this.updateProcess(id, {
37
38
  lines: process.lines.concat(newLines)
@@ -39,7 +40,7 @@ export class ProcessStore {
39
40
  }
40
41
  }
41
42
  getProcess(id) {
42
- return this.processes.find((p)=>p.id === id);
43
+ return arrayFind(this.processes, (p)=>p.id === id);
43
44
  }
44
45
  // Get rendered lines from terminal buffer or fallback to lines array
45
46
  getProcessLines(id) {
@@ -239,7 +240,7 @@ export class ProcessStore {
239
240
  };
240
241
  this.getCompletedProcesses = ()=>{
241
242
  // Return in completion order
242
- return this.completedIds.map((id)=>this.processes.find((p)=>p.id === id)).filter((p)=>p !== undefined);
243
+ return this.completedIds.map((id)=>arrayFind(this.processes, (p)=>p.id === id)).filter((p)=>p !== undefined);
243
244
  };
244
245
  this.getFailedProcesses = ()=>{
245
246
  return this.processes.filter((p)=>p.state === 'error');
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/OpenSource/node/spawn-term/src/state/processStore.ts"],"sourcesContent":["import { DEFAULT_COLUMN_WIDTH } from '../constants.ts';\nimport type { ChildProcess, Line, SessionOptions } from '../types.ts';\nimport { LineType } from '../types.ts';\n\ntype Listener = () => void;\ntype Mode = 'normal' | 'interactive';\n\nexport class ProcessStore {\n private processes: ChildProcess[] = [];\n private completedIds: string[] = []; // Track completion order\n private listeners = new Set<Listener>();\n private shouldExit = false;\n private exitCallback: (() => void) | null = null;\n\n // UI state\n private mode: Mode = 'normal';\n private selectedIndex = 0;\n private expandedId: string | null = null;\n private scrollOffset = 0;\n private listScrollOffset = 0; // Viewport offset for process list\n private errorFooterExpanded = false; // For non-interactive error footer\n private bufferVersion = 0; // Increments on every notify() to trigger re-renders\n\n // Session-level display settings (set once at session creation)\n private header: string | undefined;\n private showStatusBar = false;\n private isInteractive = false;\n\n constructor(options: SessionOptions = {}) {\n this.header = options.header;\n this.showStatusBar = options.showStatusBar ?? false;\n this.isInteractive = options.interactive ?? false;\n }\n\n // useSyncExternalStore API\n subscribe = (listener: Listener): (() => void) => {\n this.listeners.add(listener);\n return () => this.listeners.delete(listener);\n };\n\n getSnapshot = (): ChildProcess[] => this.processes;\n\n // Filtered getters\n getRunningProcesses = (): ChildProcess[] => {\n return this.processes.filter((p) => p.state === 'running');\n };\n\n getCompletedProcesses = (): ChildProcess[] => {\n // Return in completion order\n return this.completedIds.map((id) => this.processes.find((p) => p.id === id)).filter((p): p is ChildProcess => p !== undefined);\n };\n\n getFailedProcesses = (): ChildProcess[] => {\n return this.processes.filter((p) => p.state === 'error');\n };\n\n // Counts\n getRunningCount = (): number => this.processes.filter((p) => p.state === 'running').length;\n getMaxGroupLength = (): number => {\n if (this.processes.length === 0) return DEFAULT_COLUMN_WIDTH;\n return Math.max(...this.processes.map((p) => (p.group || p.title).length));\n };\n getDoneCount = (): number => this.processes.filter((p) => p.state !== 'running').length;\n getErrorCount = (): number => this.processes.filter((p) => p.state === 'error').length;\n getErrorLineCount = (): number => {\n return this.processes.filter((p) => p.state === 'error').reduce((total, p) => total + this.getProcessLineCount(p.id), 0);\n };\n\n // UI state getters\n getMode = (): Mode => this.mode;\n getSelectedIndex = (): number => this.selectedIndex;\n getExpandedId = (): string | null => this.expandedId;\n getScrollOffset = (): number => this.scrollOffset;\n getListScrollOffset = (): number => this.listScrollOffset;\n getErrorFooterExpanded = (): boolean => this.errorFooterExpanded;\n getBufferVersion = (): number => this.bufferVersion;\n // Session-level getters (set at session creation, immutable)\n getHeader = (): string | undefined => this.header;\n getShowStatusBar = (): boolean => this.showStatusBar;\n getIsInteractive = (): boolean => this.isInteractive;\n isAllComplete = (): boolean => this.processes.length > 0 && this.processes.every((p) => p.state !== 'running');\n\n // Mutations - Ink handles render throttling at 30 FPS\n addProcess(process: ChildProcess): void {\n this.processes = [...this.processes, process];\n this.notify();\n }\n\n updateProcess(id: string, update: Partial<ChildProcess>): void {\n const oldProcess = this.processes.find((p) => p.id === id);\n const wasRunning = oldProcess?.state === 'running';\n const isNowComplete = update.state && update.state !== 'running';\n\n this.processes = this.processes.map((p) => (p.id === id ? { ...p, ...update } : p));\n\n // Track completion order\n if (wasRunning && isNowComplete && !this.completedIds.includes(id)) {\n this.completedIds = [...this.completedIds, id];\n }\n\n // Auto-expand error footer when all complete with errors (non-interactive only)\n if (!this.isInteractive && this.isAllComplete() && this.getErrorCount() > 0) {\n this.errorFooterExpanded = true;\n }\n\n this.notify();\n }\n\n appendLines(id: string, newLines: Line[]): void {\n const process = this.processes.find((p) => p.id === id);\n if (process) {\n this.updateProcess(id, { lines: process.lines.concat(newLines) });\n }\n }\n\n getProcess(id: string): ChildProcess | undefined {\n return this.processes.find((p) => p.id === id);\n }\n\n // Get rendered lines from terminal buffer or fallback to lines array\n getProcessLines(id: string): Line[] {\n const process = this.getProcess(id);\n if (!process) return [];\n if (process.terminalBuffer) {\n return process.terminalBuffer.getLines().map((text) => ({\n type: LineType.stdout,\n text,\n }));\n }\n return process.lines;\n }\n\n // Get line count from terminal buffer or lines array\n getProcessLineCount(id: string): number {\n const process = this.getProcess(id);\n if (!process) return 0;\n if (process.terminalBuffer) {\n return process.terminalBuffer.lineCount;\n }\n return process.lines.length;\n }\n\n // UI state mutations\n setMode(mode: Mode): void {\n this.mode = mode;\n if (mode === 'interactive') {\n this.selectedIndex = 0;\n }\n this.notify();\n }\n\n // Interactive mode navigation\n selectNext(visibleCount?: number): void {\n if (this.processes.length > 0) {\n this.selectedIndex = (this.selectedIndex + 1) % this.processes.length;\n this.adjustListScroll(visibleCount);\n this.notify();\n }\n }\n\n selectPrev(visibleCount?: number): void {\n if (this.processes.length > 0) {\n this.selectedIndex = (this.selectedIndex - 1 + this.processes.length) % this.processes.length;\n this.adjustListScroll(visibleCount);\n this.notify();\n }\n }\n\n private adjustListScroll(visibleCount?: number): void {\n if (!visibleCount || visibleCount <= 0) return;\n\n // Ensure selected item is visible in viewport\n if (this.selectedIndex < this.listScrollOffset) {\n // Selected is above viewport - scroll up\n this.listScrollOffset = this.selectedIndex;\n } else if (this.selectedIndex >= this.listScrollOffset + visibleCount) {\n // Selected is below viewport - scroll down\n this.listScrollOffset = this.selectedIndex - visibleCount + 1;\n }\n }\n\n getSelectedProcess(): ChildProcess | undefined {\n return this.processes[this.selectedIndex];\n }\n\n // Error footer methods (for non-interactive mode)\n toggleErrorFooter(): void {\n this.errorFooterExpanded = !this.errorFooterExpanded;\n this.notify();\n }\n\n expandErrorFooter(): void {\n if (!this.errorFooterExpanded) {\n this.errorFooterExpanded = true;\n this.notify();\n }\n }\n\n getErrorLines(): Array<{ processName: string; lines: Line[] }> {\n return this.getFailedProcesses().map((p) => ({\n processName: p.group || p.title,\n lines: this.getProcessLines(p.id),\n }));\n }\n\n // Expansion methods\n toggleExpand(): void {\n const selected = this.getSelectedProcess();\n if (!selected) return;\n\n if (this.expandedId === selected.id) {\n // Collapse\n this.expandedId = null;\n this.scrollOffset = 0;\n } else {\n // Expand\n this.expandedId = selected.id;\n this.scrollOffset = 0;\n }\n this.notify();\n }\n\n collapse(): void {\n this.expandedId = null;\n this.scrollOffset = 0;\n this.notify();\n }\n\n scrollDown(maxVisible: number): void {\n if (!this.expandedId) return;\n const lineCount = this.getProcessLineCount(this.expandedId);\n if (lineCount === 0) return;\n\n const maxOffset = Math.max(0, lineCount - maxVisible);\n if (this.scrollOffset < maxOffset) {\n this.scrollOffset++;\n this.notify();\n }\n }\n\n scrollUp(): void {\n if (!this.expandedId) return;\n if (this.scrollOffset > 0) {\n this.scrollOffset--;\n this.notify();\n }\n }\n\n // Page scrolling (scroll by maxVisible lines at once)\n scrollPageDown(maxVisible: number): void {\n if (!this.expandedId) return;\n const lineCount = this.getProcessLineCount(this.expandedId);\n if (lineCount === 0) return;\n\n const maxOffset = Math.max(0, lineCount - maxVisible);\n this.scrollOffset = Math.min(this.scrollOffset + maxVisible, maxOffset);\n this.notify();\n }\n\n scrollPageUp(maxVisible: number): void {\n if (!this.expandedId) return;\n this.scrollOffset = Math.max(0, this.scrollOffset - maxVisible);\n this.notify();\n }\n\n // Jump to top/bottom\n scrollToTop(): void {\n if (!this.expandedId) return;\n this.scrollOffset = 0;\n this.notify();\n }\n\n scrollToBottom(maxVisible: number): void {\n if (!this.expandedId) return;\n const lineCount = this.getProcessLineCount(this.expandedId);\n if (lineCount === 0) return;\n\n this.scrollOffset = Math.max(0, lineCount - maxVisible);\n this.notify();\n }\n\n // Exit signaling\n signalExit(callback: () => void): void {\n this.shouldExit = true;\n this.exitCallback = callback;\n this.notify();\n }\n\n getShouldExit = (): boolean => this.shouldExit;\n getExitCallback = (): (() => void) | null => this.exitCallback;\n\n reset(): void {\n // Dispose terminal buffers before clearing\n for (const process of this.processes) {\n process.terminalBuffer?.dispose();\n }\n this.processes = [];\n this.completedIds = [];\n this.shouldExit = false;\n this.exitCallback = null;\n this.mode = 'normal';\n this.selectedIndex = 0;\n this.expandedId = null;\n this.scrollOffset = 0;\n this.listScrollOffset = 0;\n this.errorFooterExpanded = false;\n this.header = undefined;\n }\n\n // Public notify for session to trigger updates when terminal buffer changes\n notify(): void {\n this.bufferVersion++;\n this.listeners.forEach((l) => {\n l();\n });\n }\n}\n\n// Note: No global singleton - session creates its own store instance\n"],"names":["DEFAULT_COLUMN_WIDTH","LineType","ProcessStore","addProcess","process","processes","notify","updateProcess","id","update","oldProcess","find","p","wasRunning","state","isNowComplete","map","completedIds","includes","isInteractive","isAllComplete","getErrorCount","errorFooterExpanded","appendLines","newLines","lines","concat","getProcess","getProcessLines","terminalBuffer","getLines","text","type","stdout","getProcessLineCount","lineCount","length","setMode","mode","selectedIndex","selectNext","visibleCount","adjustListScroll","selectPrev","listScrollOffset","getSelectedProcess","toggleErrorFooter","expandErrorFooter","getErrorLines","getFailedProcesses","processName","group","title","toggleExpand","selected","expandedId","scrollOffset","collapse","scrollDown","maxVisible","maxOffset","Math","max","scrollUp","scrollPageDown","min","scrollPageUp","scrollToTop","scrollToBottom","signalExit","callback","shouldExit","exitCallback","reset","dispose","header","undefined","bufferVersion","listeners","forEach","l","options","Set","showStatusBar","subscribe","listener","add","delete","getSnapshot","getRunningProcesses","filter","getCompletedProcesses","getRunningCount","getMaxGroupLength","getDoneCount","getErrorLineCount","reduce","total","getMode","getSelectedIndex","getExpandedId","getScrollOffset","getListScrollOffset","getErrorFooterExpanded","getBufferVersion","getHeader","getShowStatusBar","getIsInteractive","every","getShouldExit","getExitCallback","interactive"],"mappings":"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"}
1
+ {"version":3,"sources":["/Users/kevin/Dev/OpenSource/node/spawn-term/src/state/processStore.ts"],"sourcesContent":["import { arrayFind } from '../compat.ts';\nimport { DEFAULT_COLUMN_WIDTH } from '../constants.ts';\nimport type { ChildProcess, Line, SessionOptions } from '../types.ts';\nimport { LineType } from '../types.ts';\n\ntype Listener = () => void;\ntype Mode = 'normal' | 'interactive';\n\nexport class ProcessStore {\n private processes: ChildProcess[] = [];\n private completedIds: string[] = []; // Track completion order\n private listeners = new Set<Listener>();\n private shouldExit = false;\n private exitCallback: (() => void) | null = null;\n\n // UI state\n private mode: Mode = 'normal';\n private selectedIndex = 0;\n private expandedId: string | null = null;\n private scrollOffset = 0;\n private listScrollOffset = 0; // Viewport offset for process list\n private errorFooterExpanded = false; // For non-interactive error footer\n private bufferVersion = 0; // Increments on every notify() to trigger re-renders\n\n // Session-level display settings (set once at session creation)\n private header: string | undefined;\n private showStatusBar = false;\n private isInteractive = false;\n\n constructor(options: SessionOptions = {}) {\n this.header = options.header;\n this.showStatusBar = options.showStatusBar ?? false;\n this.isInteractive = options.interactive ?? false;\n }\n\n // useSyncExternalStore API\n subscribe = (listener: Listener): (() => void) => {\n this.listeners.add(listener);\n return () => this.listeners.delete(listener);\n };\n\n getSnapshot = (): ChildProcess[] => this.processes;\n\n // Filtered getters\n getRunningProcesses = (): ChildProcess[] => {\n return this.processes.filter((p) => p.state === 'running');\n };\n\n getCompletedProcesses = (): ChildProcess[] => {\n // Return in completion order\n return this.completedIds.map((id) => arrayFind(this.processes, (p) => p.id === id)).filter((p): p is ChildProcess => p !== undefined);\n };\n\n getFailedProcesses = (): ChildProcess[] => {\n return this.processes.filter((p) => p.state === 'error');\n };\n\n // Counts\n getRunningCount = (): number => this.processes.filter((p) => p.state === 'running').length;\n getMaxGroupLength = (): number => {\n if (this.processes.length === 0) return DEFAULT_COLUMN_WIDTH;\n return Math.max(...this.processes.map((p) => (p.group || p.title).length));\n };\n getDoneCount = (): number => this.processes.filter((p) => p.state !== 'running').length;\n getErrorCount = (): number => this.processes.filter((p) => p.state === 'error').length;\n getErrorLineCount = (): number => {\n return this.processes.filter((p) => p.state === 'error').reduce((total, p) => total + this.getProcessLineCount(p.id), 0);\n };\n\n // UI state getters\n getMode = (): Mode => this.mode;\n getSelectedIndex = (): number => this.selectedIndex;\n getExpandedId = (): string | null => this.expandedId;\n getScrollOffset = (): number => this.scrollOffset;\n getListScrollOffset = (): number => this.listScrollOffset;\n getErrorFooterExpanded = (): boolean => this.errorFooterExpanded;\n getBufferVersion = (): number => this.bufferVersion;\n // Session-level getters (set at session creation, immutable)\n getHeader = (): string | undefined => this.header;\n getShowStatusBar = (): boolean => this.showStatusBar;\n getIsInteractive = (): boolean => this.isInteractive;\n isAllComplete = (): boolean => this.processes.length > 0 && this.processes.every((p) => p.state !== 'running');\n\n // Mutations - Ink handles render throttling at 30 FPS\n addProcess(process: ChildProcess): void {\n this.processes = [...this.processes, process];\n this.notify();\n }\n\n updateProcess(id: string, update: Partial<ChildProcess>): void {\n const oldProcess = arrayFind(this.processes, (p) => p.id === id);\n const wasRunning = oldProcess?.state === 'running';\n const isNowComplete = update.state && update.state !== 'running';\n\n this.processes = this.processes.map((p) => (p.id === id ? { ...p, ...update } : p));\n\n // Track completion order\n if (wasRunning && isNowComplete && !this.completedIds.includes(id)) {\n this.completedIds = [...this.completedIds, id];\n }\n\n // Auto-expand error footer when all complete with errors (non-interactive only)\n if (!this.isInteractive && this.isAllComplete() && this.getErrorCount() > 0) {\n this.errorFooterExpanded = true;\n }\n\n this.notify();\n }\n\n appendLines(id: string, newLines: Line[]): void {\n const process = arrayFind(this.processes, (p) => p.id === id);\n if (process) {\n this.updateProcess(id, { lines: process.lines.concat(newLines) });\n }\n }\n\n getProcess(id: string): ChildProcess | undefined {\n return arrayFind(this.processes, (p) => p.id === id);\n }\n\n // Get rendered lines from terminal buffer or fallback to lines array\n getProcessLines(id: string): Line[] {\n const process = this.getProcess(id);\n if (!process) return [];\n if (process.terminalBuffer) {\n return process.terminalBuffer.getLines().map((text) => ({\n type: LineType.stdout,\n text,\n }));\n }\n return process.lines;\n }\n\n // Get line count from terminal buffer or lines array\n getProcessLineCount(id: string): number {\n const process = this.getProcess(id);\n if (!process) return 0;\n if (process.terminalBuffer) {\n return process.terminalBuffer.lineCount;\n }\n return process.lines.length;\n }\n\n // UI state mutations\n setMode(mode: Mode): void {\n this.mode = mode;\n if (mode === 'interactive') {\n this.selectedIndex = 0;\n }\n this.notify();\n }\n\n // Interactive mode navigation\n selectNext(visibleCount?: number): void {\n if (this.processes.length > 0) {\n this.selectedIndex = (this.selectedIndex + 1) % this.processes.length;\n this.adjustListScroll(visibleCount);\n this.notify();\n }\n }\n\n selectPrev(visibleCount?: number): void {\n if (this.processes.length > 0) {\n this.selectedIndex = (this.selectedIndex - 1 + this.processes.length) % this.processes.length;\n this.adjustListScroll(visibleCount);\n this.notify();\n }\n }\n\n private adjustListScroll(visibleCount?: number): void {\n if (!visibleCount || visibleCount <= 0) return;\n\n // Ensure selected item is visible in viewport\n if (this.selectedIndex < this.listScrollOffset) {\n // Selected is above viewport - scroll up\n this.listScrollOffset = this.selectedIndex;\n } else if (this.selectedIndex >= this.listScrollOffset + visibleCount) {\n // Selected is below viewport - scroll down\n this.listScrollOffset = this.selectedIndex - visibleCount + 1;\n }\n }\n\n getSelectedProcess(): ChildProcess | undefined {\n return this.processes[this.selectedIndex];\n }\n\n // Error footer methods (for non-interactive mode)\n toggleErrorFooter(): void {\n this.errorFooterExpanded = !this.errorFooterExpanded;\n this.notify();\n }\n\n expandErrorFooter(): void {\n if (!this.errorFooterExpanded) {\n this.errorFooterExpanded = true;\n this.notify();\n }\n }\n\n getErrorLines(): Array<{ processName: string; lines: Line[] }> {\n return this.getFailedProcesses().map((p) => ({\n processName: p.group || p.title,\n lines: this.getProcessLines(p.id),\n }));\n }\n\n // Expansion methods\n toggleExpand(): void {\n const selected = this.getSelectedProcess();\n if (!selected) return;\n\n if (this.expandedId === selected.id) {\n // Collapse\n this.expandedId = null;\n this.scrollOffset = 0;\n } else {\n // Expand\n this.expandedId = selected.id;\n this.scrollOffset = 0;\n }\n this.notify();\n }\n\n collapse(): void {\n this.expandedId = null;\n this.scrollOffset = 0;\n this.notify();\n }\n\n scrollDown(maxVisible: number): void {\n if (!this.expandedId) return;\n const lineCount = this.getProcessLineCount(this.expandedId);\n if (lineCount === 0) return;\n\n const maxOffset = Math.max(0, lineCount - maxVisible);\n if (this.scrollOffset < maxOffset) {\n this.scrollOffset++;\n this.notify();\n }\n }\n\n scrollUp(): void {\n if (!this.expandedId) return;\n if (this.scrollOffset > 0) {\n this.scrollOffset--;\n this.notify();\n }\n }\n\n // Page scrolling (scroll by maxVisible lines at once)\n scrollPageDown(maxVisible: number): void {\n if (!this.expandedId) return;\n const lineCount = this.getProcessLineCount(this.expandedId);\n if (lineCount === 0) return;\n\n const maxOffset = Math.max(0, lineCount - maxVisible);\n this.scrollOffset = Math.min(this.scrollOffset + maxVisible, maxOffset);\n this.notify();\n }\n\n scrollPageUp(maxVisible: number): void {\n if (!this.expandedId) return;\n this.scrollOffset = Math.max(0, this.scrollOffset - maxVisible);\n this.notify();\n }\n\n // Jump to top/bottom\n scrollToTop(): void {\n if (!this.expandedId) return;\n this.scrollOffset = 0;\n this.notify();\n }\n\n scrollToBottom(maxVisible: number): void {\n if (!this.expandedId) return;\n const lineCount = this.getProcessLineCount(this.expandedId);\n if (lineCount === 0) return;\n\n this.scrollOffset = Math.max(0, lineCount - maxVisible);\n this.notify();\n }\n\n // Exit signaling\n signalExit(callback: () => void): void {\n this.shouldExit = true;\n this.exitCallback = callback;\n this.notify();\n }\n\n getShouldExit = (): boolean => this.shouldExit;\n getExitCallback = (): (() => void) | null => this.exitCallback;\n\n reset(): void {\n // Dispose terminal buffers before clearing\n for (const process of this.processes) {\n process.terminalBuffer?.dispose();\n }\n this.processes = [];\n this.completedIds = [];\n this.shouldExit = false;\n this.exitCallback = null;\n this.mode = 'normal';\n this.selectedIndex = 0;\n this.expandedId = null;\n this.scrollOffset = 0;\n this.listScrollOffset = 0;\n this.errorFooterExpanded = false;\n this.header = undefined;\n }\n\n // Public notify for session to trigger updates when terminal buffer changes\n notify(): void {\n this.bufferVersion++;\n this.listeners.forEach((l) => {\n l();\n });\n }\n}\n\n// Note: No global singleton - session creates its own store instance\n"],"names":["arrayFind","DEFAULT_COLUMN_WIDTH","LineType","ProcessStore","addProcess","process","processes","notify","updateProcess","id","update","oldProcess","p","wasRunning","state","isNowComplete","map","completedIds","includes","isInteractive","isAllComplete","getErrorCount","errorFooterExpanded","appendLines","newLines","lines","concat","getProcess","getProcessLines","terminalBuffer","getLines","text","type","stdout","getProcessLineCount","lineCount","length","setMode","mode","selectedIndex","selectNext","visibleCount","adjustListScroll","selectPrev","listScrollOffset","getSelectedProcess","toggleErrorFooter","expandErrorFooter","getErrorLines","getFailedProcesses","processName","group","title","toggleExpand","selected","expandedId","scrollOffset","collapse","scrollDown","maxVisible","maxOffset","Math","max","scrollUp","scrollPageDown","min","scrollPageUp","scrollToTop","scrollToBottom","signalExit","callback","shouldExit","exitCallback","reset","dispose","header","undefined","bufferVersion","listeners","forEach","l","options","Set","showStatusBar","subscribe","listener","add","delete","getSnapshot","getRunningProcesses","filter","getCompletedProcesses","getRunningCount","getMaxGroupLength","getDoneCount","getErrorLineCount","reduce","total","getMode","getSelectedIndex","getExpandedId","getScrollOffset","getListScrollOffset","getErrorFooterExpanded","getBufferVersion","getHeader","getShowStatusBar","getIsInteractive","every","getShouldExit","getExitCallback","interactive"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "spawn-term",
3
- "version": "3.1.1",
3
+ "version": "3.1.3",
4
4
  "description": "Formats spawn with for terminal grouping",
5
5
  "keywords": [
6
6
  "spawn",