spawn-term 3.0.4 → 3.0.6

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.
Files changed (57) hide show
  1. package/dist/cjs/components/App.js +28 -56
  2. package/dist/cjs/components/App.js.map +1 -1
  3. package/dist/cjs/components/ErrorFooter.js +120 -0
  4. package/dist/cjs/components/ErrorFooter.js.map +1 -0
  5. package/dist/cjs/components/ExpandedOutput.js +0 -2
  6. package/dist/cjs/components/ExpandedOutput.js.map +1 -1
  7. package/dist/cjs/components/StatusBar.js +22 -33
  8. package/dist/cjs/components/StatusBar.js.map +1 -1
  9. package/dist/cjs/index-esm.js +4 -0
  10. package/dist/cjs/index-esm.js.map +1 -1
  11. package/dist/cjs/lib/TerminalBuffer.js +139 -0
  12. package/dist/cjs/lib/TerminalBuffer.js.map +1 -0
  13. package/dist/cjs/session.js +129 -56
  14. package/dist/cjs/session.js.map +1 -1
  15. package/dist/cjs/src/components/ErrorFooter.d.ts +11 -0
  16. package/dist/cjs/src/index-esm.d.ts +1 -0
  17. package/dist/cjs/src/lib/TerminalBuffer.d.ts +32 -0
  18. package/dist/cjs/src/state/processStore.d.ts +14 -7
  19. package/dist/cjs/src/types.d.ts +2 -0
  20. package/dist/cjs/state/processStore.js +79 -26
  21. package/dist/cjs/state/processStore.js.map +1 -1
  22. package/dist/cjs/types.js.map +1 -1
  23. package/dist/esm/components/App.js +28 -56
  24. package/dist/esm/components/App.js.map +1 -1
  25. package/dist/esm/components/ErrorFooter.js +95 -0
  26. package/dist/esm/components/ErrorFooter.js.map +1 -0
  27. package/dist/esm/components/ExpandedOutput.js +0 -2
  28. package/dist/esm/components/ExpandedOutput.js.map +1 -1
  29. package/dist/esm/components/StatusBar.js +22 -33
  30. package/dist/esm/components/StatusBar.js.map +1 -1
  31. package/dist/esm/index-esm.js +1 -0
  32. package/dist/esm/index-esm.js.map +1 -1
  33. package/dist/esm/lib/TerminalBuffer.js +62 -0
  34. package/dist/esm/lib/TerminalBuffer.js.map +1 -0
  35. package/dist/esm/session.js +112 -35
  36. package/dist/esm/session.js.map +1 -1
  37. package/dist/esm/src/components/ErrorFooter.d.ts +11 -0
  38. package/dist/esm/src/index-esm.d.ts +1 -0
  39. package/dist/esm/src/lib/TerminalBuffer.d.ts +32 -0
  40. package/dist/esm/src/state/processStore.d.ts +14 -7
  41. package/dist/esm/src/types.d.ts +2 -0
  42. package/dist/esm/state/processStore.js +53 -22
  43. package/dist/esm/state/processStore.js.map +1 -1
  44. package/dist/esm/types.js.map +1 -1
  45. package/package.json +2 -1
  46. package/dist/cjs/components/ErrorDetailModal.js +0 -115
  47. package/dist/cjs/components/ErrorDetailModal.js.map +0 -1
  48. package/dist/cjs/components/ErrorListModal.js +0 -135
  49. package/dist/cjs/components/ErrorListModal.js.map +0 -1
  50. package/dist/cjs/src/components/ErrorDetailModal.d.ts +0 -8
  51. package/dist/cjs/src/components/ErrorListModal.d.ts +0 -8
  52. package/dist/esm/components/ErrorDetailModal.js +0 -99
  53. package/dist/esm/components/ErrorDetailModal.js.map +0 -1
  54. package/dist/esm/components/ErrorListModal.js +0 -116
  55. package/dist/esm/components/ErrorListModal.js.map +0 -1
  56. package/dist/esm/src/components/ErrorDetailModal.d.ts +0 -8
  57. package/dist/esm/src/components/ErrorListModal.d.ts +0 -8
@@ -49,6 +49,10 @@ export class ProcessStore {
49
49
  id
50
50
  ];
51
51
  }
52
+ // Auto-expand error footer when all complete with errors (non-interactive only)
53
+ if (!this.isInteractive && this.isAllComplete() && this.getErrorCount() > 0) {
54
+ this.errorFooterExpanded = true;
55
+ }
52
56
  this.notify();
53
57
  }
54
58
  appendLines(id, newLines) {
@@ -62,13 +66,32 @@ export class ProcessStore {
62
66
  getProcess(id) {
63
67
  return this.processes.find((p)=>p.id === id);
64
68
  }
69
+ // Get rendered lines from terminal buffer or fallback to lines array
70
+ getProcessLines(id) {
71
+ const process = this.getProcess(id);
72
+ if (!process) return [];
73
+ if (process.terminalBuffer) {
74
+ return process.terminalBuffer.getLines().map((text)=>({
75
+ type: LineType.stdout,
76
+ text
77
+ }));
78
+ }
79
+ return process.lines;
80
+ }
81
+ // Get line count from terminal buffer or lines array
82
+ getProcessLineCount(id) {
83
+ const process = this.getProcess(id);
84
+ if (!process) return 0;
85
+ if (process.terminalBuffer) {
86
+ return process.terminalBuffer.lineCount;
87
+ }
88
+ return process.lines.length;
89
+ }
65
90
  // UI state mutations
66
91
  setMode(mode) {
67
92
  this.mode = mode;
68
93
  if (mode === 'interactive') {
69
94
  this.selectedIndex = 0;
70
- } else if (mode === 'errorList') {
71
- this.selectedErrorIndex = 0;
72
95
  }
73
96
  this.notify();
74
97
  }
@@ -101,23 +124,22 @@ export class ProcessStore {
101
124
  getSelectedProcess() {
102
125
  return this.processes[this.selectedIndex];
103
126
  }
104
- selectNextError() {
105
- const failed = this.getFailedProcesses();
106
- if (failed.length > 0) {
107
- this.selectedErrorIndex = (this.selectedErrorIndex + 1) % failed.length;
108
- this.notify();
109
- }
127
+ // Error footer methods (for non-interactive mode)
128
+ toggleErrorFooter() {
129
+ this.errorFooterExpanded = !this.errorFooterExpanded;
130
+ this.notify();
110
131
  }
111
- selectPrevError() {
112
- const failed = this.getFailedProcesses();
113
- if (failed.length > 0) {
114
- this.selectedErrorIndex = (this.selectedErrorIndex - 1 + failed.length) % failed.length;
132
+ expandErrorFooter() {
133
+ if (!this.errorFooterExpanded) {
134
+ this.errorFooterExpanded = true;
115
135
  this.notify();
116
136
  }
117
137
  }
118
- getSelectedError() {
119
- const failed = this.getFailedProcesses();
120
- return failed[this.selectedErrorIndex];
138
+ getErrorLines() {
139
+ return this.getFailedProcesses().map((p)=>({
140
+ processName: p.group || p.title,
141
+ lines: this.getProcessLines(p.id)
142
+ }));
121
143
  }
122
144
  // Expansion methods
123
145
  toggleExpand() {
@@ -141,9 +163,9 @@ export class ProcessStore {
141
163
  }
142
164
  scrollDown(maxVisible) {
143
165
  if (!this.expandedId) return;
144
- const process = this.getProcess(this.expandedId);
145
- if (!process) return;
146
- const maxOffset = Math.max(0, process.lines.length - maxVisible);
166
+ const lineCount = this.getProcessLineCount(this.expandedId);
167
+ if (lineCount === 0) return;
168
+ const maxOffset = Math.max(0, lineCount - maxVisible);
147
169
  if (this.scrollOffset < maxOffset) {
148
170
  this.scrollOffset++;
149
171
  this.notify();
@@ -163,19 +185,26 @@ export class ProcessStore {
163
185
  this.notify();
164
186
  }
165
187
  reset() {
188
+ // Dispose terminal buffers before clearing
189
+ for (const process of this.processes){
190
+ var _process_terminalBuffer;
191
+ (_process_terminalBuffer = process.terminalBuffer) === null || _process_terminalBuffer === void 0 ? void 0 : _process_terminalBuffer.dispose();
192
+ }
166
193
  this.processes = [];
167
194
  this.completedIds = [];
168
195
  this.shouldExit = false;
169
196
  this.exitCallback = null;
170
197
  this.mode = 'normal';
171
198
  this.selectedIndex = 0;
172
- this.selectedErrorIndex = 0;
173
199
  this.expandedId = null;
174
200
  this.scrollOffset = 0;
175
201
  this.listScrollOffset = 0;
202
+ this.errorFooterExpanded = false;
176
203
  this.header = undefined;
177
204
  }
205
+ // Public notify for session to trigger updates when terminal buffer changes
178
206
  notify() {
207
+ this.bufferVersion++;
179
208
  this.listeners.forEach((l)=>{
180
209
  l();
181
210
  });
@@ -189,10 +218,11 @@ export class ProcessStore {
189
218
  // UI state
190
219
  this.mode = 'normal';
191
220
  this.selectedIndex = 0;
192
- this.selectedErrorIndex = 0;
193
221
  this.expandedId = null;
194
222
  this.scrollOffset = 0;
195
223
  this.listScrollOffset = 0; // Viewport offset for process list
224
+ this.errorFooterExpanded = false; // For non-interactive error footer
225
+ this.bufferVersion = 0; // Increments on every notify() to trigger re-renders
196
226
  this.showStatusBar = false;
197
227
  this.isInteractive = false;
198
228
  // useSyncExternalStore API
@@ -221,15 +251,16 @@ export class ProcessStore {
221
251
  this.getDoneCount = ()=>this.processes.filter((p)=>p.state !== 'running').length;
222
252
  this.getErrorCount = ()=>this.processes.filter((p)=>p.state === 'error').length;
223
253
  this.getErrorLineCount = ()=>{
224
- return this.processes.filter((p)=>p.state === 'error').reduce((total, p)=>total + p.lines.filter((l)=>l.type === LineType.stderr).length, 0);
254
+ return this.processes.filter((p)=>p.state === 'error').reduce((total, p)=>total + this.getProcessLineCount(p.id), 0);
225
255
  };
226
256
  // UI state getters
227
257
  this.getMode = ()=>this.mode;
228
258
  this.getSelectedIndex = ()=>this.selectedIndex;
229
- this.getSelectedErrorIndex = ()=>this.selectedErrorIndex;
230
259
  this.getExpandedId = ()=>this.expandedId;
231
260
  this.getScrollOffset = ()=>this.scrollOffset;
232
261
  this.getListScrollOffset = ()=>this.listScrollOffset;
262
+ this.getErrorFooterExpanded = ()=>this.errorFooterExpanded;
263
+ this.getBufferVersion = ()=>this.bufferVersion;
233
264
  // Session-level getters (set at session creation, immutable)
234
265
  this.getHeader = ()=>this.header;
235
266
  this.getShowStatusBar = ()=>this.showStatusBar;
@@ -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' | 'errorList' | 'errorDetail';\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 selectedErrorIndex = 0;\n private expandedId: string | null = null;\n private scrollOffset = 0;\n private listScrollOffset = 0; // Viewport offset for process list\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 + p.lines.filter((l) => l.type === LineType.stderr).length, 0);\n };\n\n // UI state getters\n getMode = (): Mode => this.mode;\n getSelectedIndex = (): number => this.selectedIndex;\n getSelectedErrorIndex = (): number => this.selectedErrorIndex;\n getExpandedId = (): string | null => this.expandedId;\n getScrollOffset = (): number => this.scrollOffset;\n getListScrollOffset = (): number => this.listScrollOffset;\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 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 // UI state mutations\n setMode(mode: Mode): void {\n this.mode = mode;\n if (mode === 'interactive') {\n this.selectedIndex = 0;\n } else if (mode === 'errorList') {\n this.selectedErrorIndex = 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 selectNextError(): void {\n const failed = this.getFailedProcesses();\n if (failed.length > 0) {\n this.selectedErrorIndex = (this.selectedErrorIndex + 1) % failed.length;\n this.notify();\n }\n }\n\n selectPrevError(): void {\n const failed = this.getFailedProcesses();\n if (failed.length > 0) {\n this.selectedErrorIndex = (this.selectedErrorIndex - 1 + failed.length) % failed.length;\n this.notify();\n }\n }\n\n getSelectedError(): ChildProcess | undefined {\n const failed = this.getFailedProcesses();\n return failed[this.selectedErrorIndex];\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 process = this.getProcess(this.expandedId);\n if (!process) return;\n\n const maxOffset = Math.max(0, process.lines.length - 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 // 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 this.processes = [];\n this.completedIds = [];\n this.shouldExit = false;\n this.exitCallback = null;\n this.mode = 'normal';\n this.selectedIndex = 0;\n this.selectedErrorIndex = 0;\n this.expandedId = null;\n this.scrollOffset = 0;\n this.listScrollOffset = 0;\n this.header = undefined;\n }\n\n private notify(): void {\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","appendLines","newLines","lines","concat","getProcess","setMode","mode","selectedIndex","selectedErrorIndex","selectNext","visibleCount","length","adjustListScroll","selectPrev","listScrollOffset","getSelectedProcess","selectNextError","failed","getFailedProcesses","selectPrevError","getSelectedError","toggleExpand","selected","expandedId","scrollOffset","collapse","scrollDown","maxVisible","maxOffset","Math","max","scrollUp","signalExit","callback","shouldExit","exitCallback","reset","header","undefined","listeners","forEach","l","options","Set","showStatusBar","isInteractive","subscribe","listener","add","delete","getSnapshot","getRunningProcesses","filter","getCompletedProcesses","getRunningCount","getMaxGroupLength","group","title","getDoneCount","getErrorCount","getErrorLineCount","reduce","total","type","stderr","getMode","getSelectedIndex","getSelectedErrorIndex","getExpandedId","getScrollOffset","getListScrollOffset","getHeader","getShowStatusBar","getIsInteractive","isAllComplete","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 { 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 // 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","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 +1 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/OpenSource/node/spawn-term/src/types.ts"],"sourcesContent":["export type { SpawnCallback, SpawnError, SpawnOptions, SpawnResult } from 'cross-spawn-cb';\n\nimport type { SpawnError, SpawnResult } from 'cross-spawn-cb';\n\n// Session-level options (set at session creation, immutable)\nexport type SessionOptions = {\n header?: string;\n showStatusBar?: boolean;\n interactive?: boolean;\n};\n\n// Per-process options (set when spawning each process)\nexport type ProcessOptions = {\n group?: string;\n expanded?: boolean;\n};\n\nexport type TerminalCallback = (error?: SpawnError, result?: SpawnResult) => undefined;\n\nexport const LineType = {\n stdout: 1,\n stderr: 2,\n} as const;\n\nexport type Line = {\n type: (typeof LineType)[keyof typeof LineType];\n text: string;\n};\n\nexport type State = 'running' | 'error' | 'success';\n\n// Internal representation of a child process\nexport type ChildProcess = {\n id: string;\n group?: string;\n title: string;\n state: State;\n lines: Line[];\n expanded?: boolean;\n};\n"],"names":["LineType","stdout","stderr"],"mappings":"AAmBA,OAAO,MAAMA,WAAW;IACtBC,QAAQ;IACRC,QAAQ;AACV,EAAW"}
1
+ {"version":3,"sources":["/Users/kevin/Dev/OpenSource/node/spawn-term/src/types.ts"],"sourcesContent":["export type { SpawnCallback, SpawnError, SpawnOptions, SpawnResult } from 'cross-spawn-cb';\n\nimport type { SpawnError, SpawnResult } from 'cross-spawn-cb';\n\n// Session-level options (set at session creation, immutable)\nexport type SessionOptions = {\n header?: string;\n showStatusBar?: boolean;\n interactive?: boolean;\n};\n\n// Per-process options (set when spawning each process)\nexport type ProcessOptions = {\n group?: string;\n expanded?: boolean;\n};\n\nexport type TerminalCallback = (error?: SpawnError, result?: SpawnResult) => undefined;\n\nexport const LineType = {\n stdout: 1,\n stderr: 2,\n} as const;\n\nexport type Line = {\n type: (typeof LineType)[keyof typeof LineType];\n text: string;\n};\n\nexport type State = 'running' | 'error' | 'success';\n\n// Import type for TerminalBuffer (avoid circular dependency)\nimport type { TerminalBuffer } from './lib/TerminalBuffer.ts';\n\n// Internal representation of a child process\nexport type ChildProcess = {\n id: string;\n group?: string;\n title: string;\n state: State;\n lines: Line[];\n terminalBuffer?: TerminalBuffer; // Virtual terminal for ANSI interpretation\n expanded?: boolean;\n};\n"],"names":["LineType","stdout","stderr"],"mappings":"AAmBA,OAAO,MAAMA,WAAW;IACtBC,QAAQ;IACRC,QAAQ;AACV,EAAW"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "spawn-term",
3
- "version": "3.0.4",
3
+ "version": "3.0.6",
4
4
  "description": "Formats spawn with for terminal grouping",
5
5
  "keywords": [
6
6
  "spawn",
@@ -41,6 +41,7 @@
41
41
  "version": "tsds version"
42
42
  },
43
43
  "dependencies": {
44
+ "@xterm/headless": "^5.5.0",
44
45
  "cross-spawn-cb": "*",
45
46
  "ink": "*",
46
47
  "on-one": "*",
@@ -1,115 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", {
3
- value: true
4
- });
5
- Object.defineProperty(exports, "default", {
6
- enumerable: true,
7
- get: function() {
8
- return _default;
9
- }
10
- });
11
- var _jsxruntime = require("react/jsx-runtime");
12
- var _ink = require("ink");
13
- var _react = require("react");
14
- var _typests = require("../types.js");
15
- var _default = /*#__PURE__*/ (0, _react.memo)(function ErrorDetailModal(param) {
16
- var error = param.error, currentIndex = param.currentIndex, totalErrors = param.totalErrors;
17
- var stdout = (0, _ink.useStdout)().stdout;
18
- var width = (stdout === null || stdout === void 0 ? void 0 : stdout.columns) || 80;
19
- var borderH = '─'.repeat(width - 2);
20
- var title = " Error Detail (".concat(currentIndex + 1, "/").concat(totalErrors, ") ");
21
- var titleBorder = "┌".concat(title).concat(borderH.slice(title.length + 1), "┐");
22
- var name = error.group || error.title;
23
- var stderrLines = error.lines.filter(function(l) {
24
- return l.type === _typests.LineType.stderr;
25
- });
26
- return /*#__PURE__*/ (0, _jsxruntime.jsxs)(_ink.Box, {
27
- flexDirection: "column",
28
- children: [
29
- /*#__PURE__*/ (0, _jsxruntime.jsx)(_ink.Text, {
30
- children: titleBorder
31
- }),
32
- /*#__PURE__*/ (0, _jsxruntime.jsx)(_ink.Box, {
33
- paddingX: 1,
34
- children: /*#__PURE__*/ (0, _jsxruntime.jsx)(_ink.Text, {
35
- bold: true,
36
- children: name
37
- })
38
- }),
39
- /*#__PURE__*/ (0, _jsxruntime.jsxs)(_ink.Box, {
40
- paddingX: 1,
41
- children: [
42
- /*#__PURE__*/ (0, _jsxruntime.jsx)(_ink.Text, {
43
- dimColor: true,
44
- children: "Command: "
45
- }),
46
- /*#__PURE__*/ (0, _jsxruntime.jsx)(_ink.Text, {
47
- children: error.title
48
- })
49
- ]
50
- }),
51
- /*#__PURE__*/ (0, _jsxruntime.jsx)(_ink.Box, {
52
- paddingX: 1,
53
- children: /*#__PURE__*/ (0, _jsxruntime.jsx)(_ink.Text, {
54
- dimColor: true,
55
- children: '─'.repeat(width - 4)
56
- })
57
- }),
58
- /*#__PURE__*/ (0, _jsxruntime.jsx)(_ink.Box, {
59
- paddingX: 1,
60
- children: /*#__PURE__*/ (0, _jsxruntime.jsx)(_ink.Text, {
61
- dimColor: true,
62
- children: "stderr:"
63
- })
64
- }),
65
- /*#__PURE__*/ (0, _jsxruntime.jsx)(_ink.Box, {
66
- flexDirection: "column",
67
- paddingX: 2,
68
- children: stderrLines.length === 0 ? /*#__PURE__*/ (0, _jsxruntime.jsx)(_ink.Text, {
69
- dimColor: true,
70
- children: "(no stderr output)"
71
- }) : stderrLines.map(function(line, index) {
72
- return /*#__PURE__*/ (0, _jsxruntime.jsx)(_ink.Text, {
73
- color: "red",
74
- children: line.text
75
- }, "stderr-".concat(index, "-").concat(line.text.slice(0, 20)));
76
- })
77
- }),
78
- /*#__PURE__*/ (0, _jsxruntime.jsx)(_ink.Box, {
79
- paddingX: 1,
80
- children: /*#__PURE__*/ (0, _jsxruntime.jsx)(_ink.Text, {
81
- children: " "
82
- })
83
- }),
84
- /*#__PURE__*/ (0, _jsxruntime.jsxs)(_ink.Text, {
85
- children: [
86
- "├",
87
- borderH,
88
- "┤"
89
- ]
90
- }),
91
- /*#__PURE__*/ (0, _jsxruntime.jsxs)(_ink.Box, {
92
- paddingX: 1,
93
- justifyContent: "space-between",
94
- children: [
95
- /*#__PURE__*/ (0, _jsxruntime.jsx)(_ink.Text, {
96
- dimColor: true,
97
- children: "[↑↓] prev/next error"
98
- }),
99
- /*#__PURE__*/ (0, _jsxruntime.jsx)(_ink.Text, {
100
- dimColor: true,
101
- children: "[Esc] back to list"
102
- })
103
- ]
104
- }),
105
- /*#__PURE__*/ (0, _jsxruntime.jsxs)(_ink.Text, {
106
- children: [
107
- "└",
108
- borderH,
109
- "┘"
110
- ]
111
- })
112
- ]
113
- });
114
- });
115
- /* 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; }
@@ -1 +0,0 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/OpenSource/node/spawn-term/src/components/ErrorDetailModal.tsx"],"sourcesContent":["import { Box, Text, useStdout } from 'ink';\nimport { memo } from 'react';\nimport type { ChildProcess } from '../types.ts';\nimport { LineType } from '../types.ts';\n\ntype Props = {\n error: ChildProcess;\n currentIndex: number;\n totalErrors: number;\n};\n\nexport default memo(function ErrorDetailModal({ error, currentIndex, totalErrors }: Props) {\n const { stdout } = useStdout();\n const width = stdout?.columns || 80;\n\n const borderH = '─'.repeat(width - 2);\n const title = ` Error Detail (${currentIndex + 1}/${totalErrors}) `;\n const titleBorder = `┌${title}${borderH.slice(title.length + 1)}┐`;\n\n const name = error.group || error.title;\n const stderrLines = error.lines.filter((l) => l.type === LineType.stderr);\n\n return (\n <Box flexDirection=\"column\">\n {/* Top border with title */}\n <Text>{titleBorder}</Text>\n\n {/* Process name */}\n <Box paddingX={1}>\n <Text bold>{name}</Text>\n </Box>\n\n {/* Command */}\n <Box paddingX={1}>\n <Text dimColor>Command: </Text>\n <Text>{error.title}</Text>\n </Box>\n\n {/* Separator */}\n <Box paddingX={1}>\n <Text dimColor>{'─'.repeat(width - 4)}</Text>\n </Box>\n\n {/* Error output */}\n <Box paddingX={1}>\n <Text dimColor>stderr:</Text>\n </Box>\n\n {/* Error lines in a box */}\n <Box flexDirection=\"column\" paddingX={2}>\n {stderrLines.length === 0 ? (\n <Text dimColor>(no stderr output)</Text>\n ) : (\n stderrLines.map((line, index) => (\n <Text key={`stderr-${index}-${line.text.slice(0, 20)}`} color=\"red\">\n {line.text}\n </Text>\n ))\n )}\n </Box>\n\n {/* Empty line for padding */}\n <Box paddingX={1}>\n <Text> </Text>\n </Box>\n\n {/* Bottom border with hints */}\n <Text>├{borderH}┤</Text>\n <Box paddingX={1} justifyContent=\"space-between\">\n <Text dimColor>[↑↓] prev/next error</Text>\n <Text dimColor>[Esc] back to list</Text>\n </Box>\n <Text>└{borderH}┘</Text>\n </Box>\n );\n});\n"],"names":["memo","ErrorDetailModal","error","currentIndex","totalErrors","stdout","useStdout","width","columns","borderH","repeat","title","titleBorder","slice","length","name","group","stderrLines","lines","filter","l","type","LineType","stderr","Box","flexDirection","Text","paddingX","bold","dimColor","map","line","index","color","text","justifyContent"],"mappings":";;;;+BAWA;;;eAAA;;;;mBAXqC;qBAChB;uBAEI;IAQzB,yBAAeA,IAAAA,WAAI,EAAC,SAASC,iBAAiB,KAA2C;QAAzCC,QAAF,MAAEA,OAAOC,eAAT,MAASA,cAAcC,cAAvB,MAAuBA;IACnE,IAAM,AAAEC,SAAWC,IAAAA,cAAS,IAApBD;IACR,IAAME,QAAQF,CAAAA,mBAAAA,6BAAAA,OAAQG,OAAO,KAAI;IAEjC,IAAMC,UAAU,IAAIC,MAAM,CAACH,QAAQ;IACnC,IAAMI,QAAQ,AAAC,kBAAqCP,OAApBD,eAAe,GAAE,KAAe,OAAZC,aAAY;IAChE,IAAMQ,cAAc,AAAC,IAAWH,OAARE,OAAwC,OAAhCF,QAAQI,KAAK,CAACF,MAAMG,MAAM,GAAG,IAAG;IAEhE,IAAMC,OAAOb,MAAMc,KAAK,IAAId,MAAMS,KAAK;IACvC,IAAMM,cAAcf,MAAMgB,KAAK,CAACC,MAAM,CAAC,SAACC;eAAMA,EAAEC,IAAI,KAAKC,iBAAQ,CAACC,MAAM;;IAExE,qBACE,sBAACC,QAAG;QAACC,eAAc;;0BAEjB,qBAACC,SAAI;0BAAEd;;0BAGP,qBAACY,QAAG;gBAACG,UAAU;0BACb,cAAA,qBAACD,SAAI;oBAACE,IAAI;8BAAEb;;;0BAId,sBAACS,QAAG;gBAACG,UAAU;;kCACb,qBAACD,SAAI;wBAACG,QAAQ;kCAAC;;kCACf,qBAACH,SAAI;kCAAExB,MAAMS,KAAK;;;;0BAIpB,qBAACa,QAAG;gBAACG,UAAU;0BACb,cAAA,qBAACD,SAAI;oBAACG,QAAQ;8BAAE,IAAInB,MAAM,CAACH,QAAQ;;;0BAIrC,qBAACiB,QAAG;gBAACG,UAAU;0BACb,cAAA,qBAACD,SAAI;oBAACG,QAAQ;8BAAC;;;0BAIjB,qBAACL,QAAG;gBAACC,eAAc;gBAASE,UAAU;0BACnCV,YAAYH,MAAM,KAAK,kBACtB,qBAACY,SAAI;oBAACG,QAAQ;8BAAC;qBAEfZ,YAAYa,GAAG,CAAC,SAACC,MAAMC;yCACrB,qBAACN,SAAI;wBAAmDO,OAAM;kCAC3DF,KAAKG,IAAI;uBADD,AAAC,UAAkBH,OAATC,OAAM,KAA0B,OAAvBD,KAAKG,IAAI,CAACrB,KAAK,CAAC,GAAG;;;0BAQvD,qBAACW,QAAG;gBAACG,UAAU;0BACb,cAAA,qBAACD,SAAI;8BAAC;;;0BAIR,sBAACA,SAAI;;oBAAC;oBAAEjB;oBAAQ;;;0BAChB,sBAACe,QAAG;gBAACG,UAAU;gBAAGQ,gBAAe;;kCAC/B,qBAACT,SAAI;wBAACG,QAAQ;kCAAC;;kCACf,qBAACH,SAAI;wBAACG,QAAQ;kCAAC;;;;0BAEjB,sBAACH,SAAI;;oBAAC;oBAAEjB;oBAAQ;;;;;AAGtB"}
@@ -1,135 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", {
3
- value: true
4
- });
5
- Object.defineProperty(exports, "default", {
6
- enumerable: true,
7
- get: function() {
8
- return _default;
9
- }
10
- });
11
- var _jsxruntime = require("react/jsx-runtime");
12
- var _ink = require("ink");
13
- var _react = require("react");
14
- var _figurests = /*#__PURE__*/ _interop_require_default(require("../lib/figures.js"));
15
- var _typests = require("../types.js");
16
- function _interop_require_default(obj) {
17
- return obj && obj.__esModule ? obj : {
18
- default: obj
19
- };
20
- }
21
- function truncate(str, maxLength) {
22
- if (str.length <= maxLength) return str;
23
- return "".concat(str.slice(0, maxLength - 1), "…");
24
- }
25
- function getErrorLineCount(process) {
26
- return process.lines.filter(function(l) {
27
- return l.type === _typests.LineType.stderr;
28
- }).length;
29
- }
30
- var _default = /*#__PURE__*/ (0, _react.memo)(function ErrorListModal(param) {
31
- var errors = param.errors, selectedIndex = param.selectedIndex, totalErrorLines = param.totalErrorLines;
32
- var stdout = (0, _ink.useStdout)().stdout;
33
- var width = (stdout === null || stdout === void 0 ? void 0 : stdout.columns) || 80;
34
- var innerWidth = width - 4; // 2 chars padding each side
35
- var borderH = '─'.repeat(width - 2);
36
- var title = ' Errors ';
37
- var titleBorder = "┌".concat(title).concat(borderH.slice(title.length + 1), "┐");
38
- return /*#__PURE__*/ (0, _jsxruntime.jsxs)(_ink.Box, {
39
- flexDirection: "column",
40
- children: [
41
- /*#__PURE__*/ (0, _jsxruntime.jsx)(_ink.Text, {
42
- children: titleBorder
43
- }),
44
- /*#__PURE__*/ (0, _jsxruntime.jsx)(_ink.Box, {
45
- paddingX: 1,
46
- children: /*#__PURE__*/ (0, _jsxruntime.jsxs)(_ink.Text, {
47
- children: [
48
- errors.length,
49
- " process",
50
- errors.length !== 1 ? 'es' : '',
51
- " failed (",
52
- totalErrorLines,
53
- " error line",
54
- totalErrorLines !== 1 ? 's' : '',
55
- " total)"
56
- ]
57
- })
58
- }),
59
- /*#__PURE__*/ (0, _jsxruntime.jsx)(_ink.Box, {
60
- paddingX: 1,
61
- children: /*#__PURE__*/ (0, _jsxruntime.jsx)(_ink.Text, {
62
- children: " "
63
- })
64
- }),
65
- errors.map(function(error, index) {
66
- var isSelected = index === selectedIndex;
67
- var indicator = isSelected ? _figurests.default.pointer : ' ';
68
- var name = error.group || error.title;
69
- var lineCount = getErrorLineCount(error);
70
- var lineText = "".concat(lineCount, " line").concat(lineCount !== 1 ? 's' : '');
71
- // Calculate available space for name
72
- var prefixLen = 3; // indicator + space + space
73
- var suffixLen = lineText.length + 2; // space + lineText
74
- var maxNameLen = innerWidth - prefixLen - suffixLen;
75
- var truncatedName = truncate(name, maxNameLen);
76
- return /*#__PURE__*/ (0, _jsxruntime.jsxs)(_ink.Box, {
77
- paddingX: 1,
78
- children: [
79
- /*#__PURE__*/ (0, _jsxruntime.jsxs)(_ink.Text, {
80
- color: isSelected ? 'cyan' : undefined,
81
- bold: isSelected,
82
- children: [
83
- indicator,
84
- " ",
85
- truncatedName
86
- ]
87
- }),
88
- /*#__PURE__*/ (0, _jsxruntime.jsx)(_ink.Box, {
89
- flexGrow: 1
90
- }),
91
- /*#__PURE__*/ (0, _jsxruntime.jsx)(_ink.Text, {
92
- dimColor: true,
93
- children: lineText
94
- })
95
- ]
96
- }, error.id);
97
- }),
98
- /*#__PURE__*/ (0, _jsxruntime.jsx)(_ink.Box, {
99
- paddingX: 1,
100
- children: /*#__PURE__*/ (0, _jsxruntime.jsx)(_ink.Text, {
101
- children: " "
102
- })
103
- }),
104
- /*#__PURE__*/ (0, _jsxruntime.jsxs)(_ink.Text, {
105
- children: [
106
- "├",
107
- borderH,
108
- "┤"
109
- ]
110
- }),
111
- /*#__PURE__*/ (0, _jsxruntime.jsxs)(_ink.Box, {
112
- paddingX: 1,
113
- justifyContent: "space-between",
114
- children: [
115
- /*#__PURE__*/ (0, _jsxruntime.jsx)(_ink.Text, {
116
- dimColor: true,
117
- children: "[↑↓] navigate [Enter] view details"
118
- }),
119
- /*#__PURE__*/ (0, _jsxruntime.jsx)(_ink.Text, {
120
- dimColor: true,
121
- children: "[Esc] close"
122
- })
123
- ]
124
- }),
125
- /*#__PURE__*/ (0, _jsxruntime.jsxs)(_ink.Text, {
126
- children: [
127
- "└",
128
- borderH,
129
- "┘"
130
- ]
131
- })
132
- ]
133
- });
134
- });
135
- /* 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; }
@@ -1 +0,0 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/OpenSource/node/spawn-term/src/components/ErrorListModal.tsx"],"sourcesContent":["import { Box, Text, useStdout } from 'ink';\nimport { memo } from 'react';\nimport figures from '../lib/figures.ts';\nimport type { ChildProcess } from '../types.ts';\nimport { LineType } from '../types.ts';\n\ntype Props = {\n errors: ChildProcess[];\n selectedIndex: number;\n totalErrorLines: number;\n};\n\nfunction truncate(str: string, maxLength: number): string {\n if (str.length <= maxLength) return str;\n return `${str.slice(0, maxLength - 1)}…`;\n}\n\nfunction getErrorLineCount(process: ChildProcess): number {\n return process.lines.filter((l) => l.type === LineType.stderr).length;\n}\n\nexport default memo(function ErrorListModal({ errors, selectedIndex, totalErrorLines }: Props) {\n const { stdout } = useStdout();\n const width = stdout?.columns || 80;\n const innerWidth = width - 4; // 2 chars padding each side\n\n const borderH = '─'.repeat(width - 2);\n const title = ' Errors ';\n const titleBorder = `┌${title}${borderH.slice(title.length + 1)}┐`;\n\n return (\n <Box flexDirection=\"column\">\n {/* Top border with title */}\n <Text>{titleBorder}</Text>\n\n {/* Summary */}\n <Box paddingX={1}>\n <Text>\n {errors.length} process{errors.length !== 1 ? 'es' : ''} failed ({totalErrorLines} error line\n {totalErrorLines !== 1 ? 's' : ''} total)\n </Text>\n </Box>\n\n {/* Empty line */}\n <Box paddingX={1}>\n <Text> </Text>\n </Box>\n\n {/* Error list */}\n {errors.map((error, index) => {\n const isSelected = index === selectedIndex;\n const indicator = isSelected ? figures.pointer : ' ';\n const name = error.group || error.title;\n const lineCount = getErrorLineCount(error);\n const lineText = `${lineCount} line${lineCount !== 1 ? 's' : ''}`;\n\n // Calculate available space for name\n const prefixLen = 3; // indicator + space + space\n const suffixLen = lineText.length + 2; // space + lineText\n const maxNameLen = innerWidth - prefixLen - suffixLen;\n const truncatedName = truncate(name, maxNameLen);\n\n return (\n <Box key={error.id} paddingX={1}>\n <Text color={isSelected ? 'cyan' : undefined} bold={isSelected}>\n {indicator} {truncatedName}\n </Text>\n <Box flexGrow={1} />\n <Text dimColor>{lineText}</Text>\n </Box>\n );\n })}\n\n {/* Empty line for padding */}\n <Box paddingX={1}>\n <Text> </Text>\n </Box>\n\n {/* Bottom border with hints */}\n <Text>├{borderH}┤</Text>\n <Box paddingX={1} justifyContent=\"space-between\">\n <Text dimColor>[↑↓] navigate [Enter] view details</Text>\n <Text dimColor>[Esc] close</Text>\n </Box>\n <Text>└{borderH}┘</Text>\n </Box>\n );\n});\n"],"names":["truncate","str","maxLength","length","slice","getErrorLineCount","process","lines","filter","l","type","LineType","stderr","memo","ErrorListModal","errors","selectedIndex","totalErrorLines","stdout","useStdout","width","columns","innerWidth","borderH","repeat","title","titleBorder","Box","flexDirection","Text","paddingX","map","error","index","isSelected","indicator","figures","pointer","name","group","lineCount","lineText","prefixLen","suffixLen","maxNameLen","truncatedName","color","undefined","bold","flexGrow","dimColor","id","justifyContent"],"mappings":";;;;+BAqBA;;;eAAA;;;;mBArBqC;qBAChB;gEACD;uBAEK;;;;;;AAQzB,SAASA,SAASC,GAAW,EAAEC,SAAiB;IAC9C,IAAID,IAAIE,MAAM,IAAID,WAAW,OAAOD;IACpC,OAAO,AAAC,GAA8B,OAA5BA,IAAIG,KAAK,CAAC,GAAGF,YAAY,IAAG;AACxC;AAEA,SAASG,kBAAkBC,OAAqB;IAC9C,OAAOA,QAAQC,KAAK,CAACC,MAAM,CAAC,SAACC;eAAMA,EAAEC,IAAI,KAAKC,iBAAQ,CAACC,MAAM;OAAET,MAAM;AACvE;IAEA,yBAAeU,IAAAA,WAAI,EAAC,SAASC,eAAe,KAAiD;QAA/CC,SAAF,MAAEA,QAAQC,gBAAV,MAAUA,eAAeC,kBAAzB,MAAyBA;IACnE,IAAM,AAAEC,SAAWC,IAAAA,cAAS,IAApBD;IACR,IAAME,QAAQF,CAAAA,mBAAAA,6BAAAA,OAAQG,OAAO,KAAI;IACjC,IAAMC,aAAaF,QAAQ,GAAG,4BAA4B;IAE1D,IAAMG,UAAU,IAAIC,MAAM,CAACJ,QAAQ;IACnC,IAAMK,QAAQ;IACd,IAAMC,cAAc,AAAC,IAAWH,OAARE,OAAwC,OAAhCF,QAAQnB,KAAK,CAACqB,MAAMtB,MAAM,GAAG,IAAG;IAEhE,qBACE,sBAACwB,QAAG;QAACC,eAAc;;0BAEjB,qBAACC,SAAI;0BAAEH;;0BAGP,qBAACC,QAAG;gBAACG,UAAU;0BACb,cAAA,sBAACD,SAAI;;wBACFd,OAAOZ,MAAM;wBAAC;wBAASY,OAAOZ,MAAM,KAAK,IAAI,OAAO;wBAAG;wBAAUc;wBAAgB;wBACjFA,oBAAoB,IAAI,MAAM;wBAAG;;;;0BAKtC,qBAACU,QAAG;gBAACG,UAAU;0BACb,cAAA,qBAACD,SAAI;8BAAC;;;YAIPd,OAAOgB,GAAG,CAAC,SAACC,OAAOC;gBAClB,IAAMC,aAAaD,UAAUjB;gBAC7B,IAAMmB,YAAYD,aAAaE,kBAAO,CAACC,OAAO,GAAG;gBACjD,IAAMC,OAAON,MAAMO,KAAK,IAAIP,MAAMP,KAAK;gBACvC,IAAMe,YAAYnC,kBAAkB2B;gBACpC,IAAMS,WAAW,AAAC,GAAmBD,OAAjBA,WAAU,SAAkC,OAA3BA,cAAc,IAAI,MAAM;gBAE7D,qCAAqC;gBACrC,IAAME,YAAY,GAAG,4BAA4B;gBACjD,IAAMC,YAAYF,SAAStC,MAAM,GAAG,GAAG,mBAAmB;gBAC1D,IAAMyC,aAAatB,aAAaoB,YAAYC;gBAC5C,IAAME,gBAAgB7C,SAASsC,MAAMM;gBAErC,qBACE,sBAACjB,QAAG;oBAAgBG,UAAU;;sCAC5B,sBAACD,SAAI;4BAACiB,OAAOZ,aAAa,SAASa;4BAAWC,MAAMd;;gCACjDC;gCAAU;gCAAEU;;;sCAEf,qBAAClB,QAAG;4BAACsB,UAAU;;sCACf,qBAACpB,SAAI;4BAACqB,QAAQ;sCAAET;;;mBALRT,MAAMmB,EAAE;YAQtB;0BAGA,qBAACxB,QAAG;gBAACG,UAAU;0BACb,cAAA,qBAACD,SAAI;8BAAC;;;0BAIR,sBAACA,SAAI;;oBAAC;oBAAEN;oBAAQ;;;0BAChB,sBAACI,QAAG;gBAACG,UAAU;gBAAGsB,gBAAe;;kCAC/B,qBAACvB,SAAI;wBAACqB,QAAQ;kCAAC;;kCACf,qBAACrB,SAAI;wBAACqB,QAAQ;kCAAC;;;;0BAEjB,sBAACrB,SAAI;;oBAAC;oBAAEN;oBAAQ;;;;;AAGtB"}
@@ -1,8 +0,0 @@
1
- import type { ChildProcess } from '../types.js';
2
- type Props = {
3
- error: ChildProcess;
4
- currentIndex: number;
5
- totalErrors: number;
6
- };
7
- declare const _default: import("react").NamedExoticComponent<Props>;
8
- export default _default;
@@ -1,8 +0,0 @@
1
- import type { ChildProcess } from '../types.js';
2
- type Props = {
3
- errors: ChildProcess[];
4
- selectedIndex: number;
5
- totalErrorLines: number;
6
- };
7
- declare const _default: import("react").NamedExoticComponent<Props>;
8
- export default _default;