spawn-term 2.0.0 → 2.1.1
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.
- package/dist/cjs/components/App.js +77 -17
- package/dist/cjs/components/App.js.map +1 -1
- package/dist/cjs/components/CompactProcessLine.js +12 -3
- package/dist/cjs/components/CompactProcessLine.js.map +1 -1
- package/dist/cjs/components/ExpandedOutput.js +55 -0
- package/dist/cjs/components/ExpandedOutput.js.map +1 -0
- package/dist/cjs/constants.js +42 -0
- package/dist/cjs/constants.js.map +1 -0
- package/dist/cjs/createApp.js +10 -11
- package/dist/cjs/createApp.js.map +1 -1
- package/dist/cjs/lib/addLines.js +58 -4
- package/dist/cjs/lib/addLines.js.map +1 -1
- package/dist/cjs/lib/format.js +21 -0
- package/dist/cjs/lib/format.js.map +1 -0
- package/dist/cjs/src/components/CompactProcessLine.d.ts +1 -0
- package/dist/cjs/src/components/ExpandedOutput.d.ts +8 -0
- package/dist/cjs/src/constants.d.ts +7 -0
- package/dist/cjs/src/lib/addLines.d.ts +6 -1
- package/dist/cjs/src/lib/format.d.ts +2 -0
- package/dist/cjs/src/state/processStore.d.ts +20 -1
- package/dist/cjs/src/types.d.ts +6 -0
- package/dist/cjs/state/processStore.js +105 -1
- package/dist/cjs/state/processStore.js.map +1 -1
- package/dist/cjs/types.js.map +1 -1
- package/dist/esm/components/App.js +77 -15
- package/dist/esm/components/App.js.map +1 -1
- package/dist/esm/components/CompactProcessLine.js +12 -3
- package/dist/esm/components/CompactProcessLine.js.map +1 -1
- package/dist/esm/components/ExpandedOutput.js +41 -0
- package/dist/esm/components/ExpandedOutput.js.map +1 -0
- package/dist/esm/constants.js +11 -0
- package/dist/esm/constants.js.map +1 -0
- package/dist/esm/createApp.js +10 -11
- package/dist/esm/createApp.js.map +1 -1
- package/dist/esm/lib/addLines.js +32 -5
- package/dist/esm/lib/addLines.js.map +1 -1
- package/dist/esm/lib/format.js +10 -0
- package/dist/esm/lib/format.js.map +1 -0
- package/dist/esm/src/components/CompactProcessLine.d.ts +1 -0
- package/dist/esm/src/components/ExpandedOutput.d.ts +8 -0
- package/dist/esm/src/constants.d.ts +7 -0
- package/dist/esm/src/lib/addLines.d.ts +6 -1
- package/dist/esm/src/lib/format.d.ts +2 -0
- package/dist/esm/src/state/processStore.d.ts +20 -1
- package/dist/esm/src/types.d.ts +6 -0
- package/dist/esm/state/processStore.js +82 -1
- package/dist/esm/state/processStore.js.map +1 -1
- package/dist/esm/types.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ChildProcess, Line } from '../types.js';
|
|
2
2
|
type Listener = () => void;
|
|
3
|
-
type Mode = 'normal' | 'errorList' | 'errorDetail';
|
|
3
|
+
type Mode = 'normal' | 'interactive' | 'errorList' | 'errorDetail';
|
|
4
4
|
declare class ProcessStore {
|
|
5
5
|
private processes;
|
|
6
6
|
private completedIds;
|
|
@@ -8,26 +8,45 @@ declare class ProcessStore {
|
|
|
8
8
|
private shouldExit;
|
|
9
9
|
private exitCallback;
|
|
10
10
|
private mode;
|
|
11
|
+
private selectedIndex;
|
|
11
12
|
private selectedErrorIndex;
|
|
13
|
+
private expandedId;
|
|
14
|
+
private scrollOffset;
|
|
15
|
+
private header;
|
|
12
16
|
subscribe: (listener: Listener) => (() => void);
|
|
13
17
|
getSnapshot: () => ChildProcess[];
|
|
14
18
|
getRunningProcesses: () => ChildProcess[];
|
|
15
19
|
getCompletedProcesses: () => ChildProcess[];
|
|
16
20
|
getFailedProcesses: () => ChildProcess[];
|
|
17
21
|
getRunningCount: () => number;
|
|
22
|
+
getMaxGroupLength: () => number;
|
|
18
23
|
getDoneCount: () => number;
|
|
19
24
|
getErrorCount: () => number;
|
|
20
25
|
getErrorLineCount: () => number;
|
|
21
26
|
getMode: () => Mode;
|
|
27
|
+
getSelectedIndex: () => number;
|
|
22
28
|
getSelectedErrorIndex: () => number;
|
|
29
|
+
getExpandedId: () => string | null;
|
|
30
|
+
getScrollOffset: () => number;
|
|
31
|
+
getHeader: () => string | undefined;
|
|
32
|
+
getShowStatusBar: () => boolean;
|
|
33
|
+
getIsInteractive: () => boolean;
|
|
34
|
+
isAllComplete: () => boolean;
|
|
23
35
|
addProcess(process: ChildProcess): void;
|
|
24
36
|
updateProcess(id: string, update: Partial<ChildProcess>): void;
|
|
25
37
|
appendLines(id: string, newLines: Line[]): void;
|
|
26
38
|
getProcess(id: string): ChildProcess | undefined;
|
|
27
39
|
setMode(mode: Mode): void;
|
|
40
|
+
selectNext(): void;
|
|
41
|
+
selectPrev(): void;
|
|
42
|
+
getSelectedProcess(): ChildProcess | undefined;
|
|
28
43
|
selectNextError(): void;
|
|
29
44
|
selectPrevError(): void;
|
|
30
45
|
getSelectedError(): ChildProcess | undefined;
|
|
46
|
+
toggleExpand(): void;
|
|
47
|
+
collapse(): void;
|
|
48
|
+
scrollDown(maxVisible: number): void;
|
|
49
|
+
scrollUp(): void;
|
|
31
50
|
signalExit(callback: () => void): void;
|
|
32
51
|
getShouldExit: () => boolean;
|
|
33
52
|
getExitCallback: () => (() => void) | null;
|
package/dist/cjs/src/types.d.ts
CHANGED
|
@@ -3,6 +3,9 @@ import type { SpawnError, SpawnResult } from 'cross-spawn-cb';
|
|
|
3
3
|
export type TerminalOptions = {
|
|
4
4
|
group?: string;
|
|
5
5
|
expanded?: boolean;
|
|
6
|
+
header?: string;
|
|
7
|
+
showStatusBar?: boolean;
|
|
8
|
+
interactive?: boolean;
|
|
6
9
|
};
|
|
7
10
|
export type TerminalCallback = (error?: SpawnError, result?: SpawnResult) => undefined;
|
|
8
11
|
export declare const LineType: {
|
|
@@ -21,4 +24,7 @@ export type ChildProcess = {
|
|
|
21
24
|
state: State;
|
|
22
25
|
lines: Line[];
|
|
23
26
|
expanded?: boolean;
|
|
27
|
+
header?: string;
|
|
28
|
+
showStatusBar?: boolean;
|
|
29
|
+
interactive?: boolean;
|
|
24
30
|
};
|
|
@@ -8,6 +8,7 @@ Object.defineProperty(exports, "processStore", {
|
|
|
8
8
|
return processStore;
|
|
9
9
|
}
|
|
10
10
|
});
|
|
11
|
+
var _constantsts = require("../constants.js");
|
|
11
12
|
var _typests = require("../types.js");
|
|
12
13
|
function _array_like_to_array(arr, len) {
|
|
13
14
|
if (len == null || len > arr.length) len = arr.length;
|
|
@@ -79,7 +80,10 @@ var ProcessStore = /*#__PURE__*/ function() {
|
|
|
79
80
|
this.exitCallback = null;
|
|
80
81
|
// UI state
|
|
81
82
|
this.mode = 'normal';
|
|
83
|
+
this.selectedIndex = 0;
|
|
82
84
|
this.selectedErrorIndex = 0;
|
|
85
|
+
this.expandedId = null;
|
|
86
|
+
this.scrollOffset = 0;
|
|
83
87
|
// useSyncExternalStore API
|
|
84
88
|
this.subscribe = function(listener) {
|
|
85
89
|
_this.listeners.add(listener);
|
|
@@ -117,6 +121,13 @@ var ProcessStore = /*#__PURE__*/ function() {
|
|
|
117
121
|
return p.state === 'running';
|
|
118
122
|
}).length;
|
|
119
123
|
};
|
|
124
|
+
this.getMaxGroupLength = function() {
|
|
125
|
+
var _Math;
|
|
126
|
+
if (_this.processes.length === 0) return _constantsts.DEFAULT_COLUMN_WIDTH;
|
|
127
|
+
return (_Math = Math).max.apply(_Math, _to_consumable_array(_this.processes.map(function(p) {
|
|
128
|
+
return (p.group || p.title).length;
|
|
129
|
+
})));
|
|
130
|
+
};
|
|
120
131
|
this.getDoneCount = function() {
|
|
121
132
|
return _this.processes.filter(function(p) {
|
|
122
133
|
return p.state !== 'running';
|
|
@@ -140,9 +151,39 @@ var ProcessStore = /*#__PURE__*/ function() {
|
|
|
140
151
|
this.getMode = function() {
|
|
141
152
|
return _this.mode;
|
|
142
153
|
};
|
|
154
|
+
this.getSelectedIndex = function() {
|
|
155
|
+
return _this.selectedIndex;
|
|
156
|
+
};
|
|
143
157
|
this.getSelectedErrorIndex = function() {
|
|
144
158
|
return _this.selectedErrorIndex;
|
|
145
159
|
};
|
|
160
|
+
this.getExpandedId = function() {
|
|
161
|
+
return _this.expandedId;
|
|
162
|
+
};
|
|
163
|
+
this.getScrollOffset = function() {
|
|
164
|
+
return _this.scrollOffset;
|
|
165
|
+
};
|
|
166
|
+
// Get header
|
|
167
|
+
this.getHeader = function() {
|
|
168
|
+
return _this.header;
|
|
169
|
+
};
|
|
170
|
+
// Show status bar only if any process sets showStatusBar: true (default: false)
|
|
171
|
+
this.getShowStatusBar = function() {
|
|
172
|
+
return _this.processes.some(function(p) {
|
|
173
|
+
return p.showStatusBar === true;
|
|
174
|
+
});
|
|
175
|
+
};
|
|
176
|
+
// Interactive mode if any process has interactive: true
|
|
177
|
+
this.getIsInteractive = function() {
|
|
178
|
+
return _this.processes.some(function(p) {
|
|
179
|
+
return p.interactive === true;
|
|
180
|
+
});
|
|
181
|
+
};
|
|
182
|
+
this.isAllComplete = function() {
|
|
183
|
+
return _this.processes.length > 0 && _this.processes.every(function(p) {
|
|
184
|
+
return p.state !== 'running';
|
|
185
|
+
});
|
|
186
|
+
};
|
|
146
187
|
this.getShouldExit = function() {
|
|
147
188
|
return _this.shouldExit;
|
|
148
189
|
};
|
|
@@ -153,6 +194,10 @@ var ProcessStore = /*#__PURE__*/ function() {
|
|
|
153
194
|
var _proto = ProcessStore.prototype;
|
|
154
195
|
// Mutations - Ink handles render throttling at 30 FPS
|
|
155
196
|
_proto.addProcess = function addProcess(process) {
|
|
197
|
+
// Set header on first process that provides one
|
|
198
|
+
if (this.header === undefined && process.header !== undefined) {
|
|
199
|
+
this.header = process.header;
|
|
200
|
+
}
|
|
156
201
|
this.processes = _to_consumable_array(this.processes).concat([
|
|
157
202
|
process
|
|
158
203
|
]);
|
|
@@ -193,11 +238,29 @@ var ProcessStore = /*#__PURE__*/ function() {
|
|
|
193
238
|
// UI state mutations
|
|
194
239
|
_proto.setMode = function setMode(mode) {
|
|
195
240
|
this.mode = mode;
|
|
196
|
-
if (mode === '
|
|
241
|
+
if (mode === 'interactive') {
|
|
242
|
+
this.selectedIndex = 0;
|
|
243
|
+
} else if (mode === 'errorList') {
|
|
197
244
|
this.selectedErrorIndex = 0;
|
|
198
245
|
}
|
|
199
246
|
this.notify();
|
|
200
247
|
};
|
|
248
|
+
// Interactive mode navigation
|
|
249
|
+
_proto.selectNext = function selectNext() {
|
|
250
|
+
if (this.processes.length > 0) {
|
|
251
|
+
this.selectedIndex = (this.selectedIndex + 1) % this.processes.length;
|
|
252
|
+
this.notify();
|
|
253
|
+
}
|
|
254
|
+
};
|
|
255
|
+
_proto.selectPrev = function selectPrev() {
|
|
256
|
+
if (this.processes.length > 0) {
|
|
257
|
+
this.selectedIndex = (this.selectedIndex - 1 + this.processes.length) % this.processes.length;
|
|
258
|
+
this.notify();
|
|
259
|
+
}
|
|
260
|
+
};
|
|
261
|
+
_proto.getSelectedProcess = function getSelectedProcess() {
|
|
262
|
+
return this.processes[this.selectedIndex];
|
|
263
|
+
};
|
|
201
264
|
_proto.selectNextError = function selectNextError() {
|
|
202
265
|
var failed = this.getFailedProcesses();
|
|
203
266
|
if (failed.length > 0) {
|
|
@@ -216,6 +279,43 @@ var ProcessStore = /*#__PURE__*/ function() {
|
|
|
216
279
|
var failed = this.getFailedProcesses();
|
|
217
280
|
return failed[this.selectedErrorIndex];
|
|
218
281
|
};
|
|
282
|
+
// Expansion methods
|
|
283
|
+
_proto.toggleExpand = function toggleExpand() {
|
|
284
|
+
var selected = this.getSelectedProcess();
|
|
285
|
+
if (!selected) return;
|
|
286
|
+
if (this.expandedId === selected.id) {
|
|
287
|
+
// Collapse
|
|
288
|
+
this.expandedId = null;
|
|
289
|
+
this.scrollOffset = 0;
|
|
290
|
+
} else {
|
|
291
|
+
// Expand
|
|
292
|
+
this.expandedId = selected.id;
|
|
293
|
+
this.scrollOffset = 0;
|
|
294
|
+
}
|
|
295
|
+
this.notify();
|
|
296
|
+
};
|
|
297
|
+
_proto.collapse = function collapse() {
|
|
298
|
+
this.expandedId = null;
|
|
299
|
+
this.scrollOffset = 0;
|
|
300
|
+
this.notify();
|
|
301
|
+
};
|
|
302
|
+
_proto.scrollDown = function scrollDown(maxVisible) {
|
|
303
|
+
if (!this.expandedId) return;
|
|
304
|
+
var process = this.getProcess(this.expandedId);
|
|
305
|
+
if (!process) return;
|
|
306
|
+
var maxOffset = Math.max(0, process.lines.length - maxVisible);
|
|
307
|
+
if (this.scrollOffset < maxOffset) {
|
|
308
|
+
this.scrollOffset++;
|
|
309
|
+
this.notify();
|
|
310
|
+
}
|
|
311
|
+
};
|
|
312
|
+
_proto.scrollUp = function scrollUp() {
|
|
313
|
+
if (!this.expandedId) return;
|
|
314
|
+
if (this.scrollOffset > 0) {
|
|
315
|
+
this.scrollOffset--;
|
|
316
|
+
this.notify();
|
|
317
|
+
}
|
|
318
|
+
};
|
|
219
319
|
// Exit signaling
|
|
220
320
|
_proto.signalExit = function signalExit(callback) {
|
|
221
321
|
this.shouldExit = true;
|
|
@@ -228,7 +328,11 @@ var ProcessStore = /*#__PURE__*/ function() {
|
|
|
228
328
|
this.shouldExit = false;
|
|
229
329
|
this.exitCallback = null;
|
|
230
330
|
this.mode = 'normal';
|
|
331
|
+
this.selectedIndex = 0;
|
|
231
332
|
this.selectedErrorIndex = 0;
|
|
333
|
+
this.expandedId = null;
|
|
334
|
+
this.scrollOffset = 0;
|
|
335
|
+
this.header = undefined;
|
|
232
336
|
};
|
|
233
337
|
_proto.notify = function notify() {
|
|
234
338
|
this.listeners.forEach(function(l) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/node/spawn-term/src/state/processStore.ts"],"sourcesContent":["import type { ChildProcess, Line } from '../types.ts';\nimport { LineType } from '../types.ts';\n\ntype Listener = () => void;\ntype Mode = 'normal' | 'errorList' | 'errorDetail';\n\nclass 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 selectedErrorIndex = 0;\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 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 getSelectedErrorIndex = (): number => this.selectedErrorIndex;\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 === 'errorList') {\n this.selectedErrorIndex = 0;\n }\n this.notify();\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 // 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.selectedErrorIndex = 0;\n }\n\n private notify(): void {\n this.listeners.forEach((l) => {\n l();\n });\n }\n}\n\nexport const processStore = new ProcessStore();\nexport type { ProcessStore };\n"],"names":["processStore","ProcessStore","processes","completedIds","listeners","Set","shouldExit","exitCallback","mode","selectedErrorIndex","subscribe","listener","add","delete","getSnapshot","getRunningProcesses","filter","p","state","getCompletedProcesses","map","id","find","undefined","getFailedProcesses","getRunningCount","length","getDoneCount","getErrorCount","getErrorLineCount","reduce","total","lines","l","type","LineType","stderr","getMode","getSelectedErrorIndex","getShouldExit","getExitCallback","addProcess","process","notify","updateProcess","update","oldProcess","wasRunning","isNowComplete","includes","appendLines","newLines","concat","getProcess","setMode","selectNextError","failed","selectPrevError","getSelectedError","signalExit","callback","reset","forEach"],"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 } from '../types.ts';\nimport { LineType } from '../types.ts';\n\ntype Listener = () => void;\ntype Mode = 'normal' | 'interactive' | 'errorList' | 'errorDetail';\n\nclass 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\n // App-level display settings\n private header: string | undefined;\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 // Get header\n getHeader = (): string | undefined => this.header;\n // Show status bar only if any process sets showStatusBar: true (default: false)\n getShowStatusBar = (): boolean => this.processes.some((p) => p.showStatusBar === true);\n // Interactive mode if any process has interactive: true\n getIsInteractive = (): boolean => this.processes.some((p) => p.interactive === true);\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 // Set header on first process that provides one\n if (this.header === undefined && process.header !== undefined) {\n this.header = process.header;\n }\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(): void {\n if (this.processes.length > 0) {\n this.selectedIndex = (this.selectedIndex + 1) % this.processes.length;\n this.notify();\n }\n }\n\n selectPrev(): void {\n if (this.processes.length > 0) {\n this.selectedIndex = (this.selectedIndex - 1 + this.processes.length) % this.processes.length;\n this.notify();\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.header = undefined;\n }\n\n private notify(): void {\n this.listeners.forEach((l) => {\n l();\n });\n }\n}\n\nexport const processStore = new ProcessStore();\nexport type { ProcessStore };\n"],"names":["processStore","ProcessStore","processes","completedIds","listeners","Set","shouldExit","exitCallback","mode","selectedIndex","selectedErrorIndex","expandedId","scrollOffset","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","lines","l","type","LineType","stderr","getMode","getSelectedIndex","getSelectedErrorIndex","getExpandedId","getScrollOffset","getHeader","header","getShowStatusBar","some","showStatusBar","getIsInteractive","interactive","isAllComplete","every","getShouldExit","getExitCallback","addProcess","process","notify","updateProcess","update","oldProcess","wasRunning","isNowComplete","includes","appendLines","newLines","concat","getProcess","setMode","selectNext","selectPrev","getSelectedProcess","selectNextError","failed","selectPrevError","getSelectedError","toggleExpand","selected","collapse","scrollDown","maxVisible","maxOffset","scrollUp","signalExit","callback","reset","forEach"],"mappings":"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"}
|
package/dist/cjs/types.js.map
CHANGED
|
@@ -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\nexport type TerminalOptions = {\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';\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":";;;;+
|
|
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\nexport type TerminalOptions = {\n group?: string;\n expanded?: boolean;\n header?: string;\n showStatusBar?: boolean;\n interactive?: 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';\nexport type ChildProcess = {\n id: string;\n group?: string;\n title: string;\n state: State;\n lines: Line[];\n expanded?: boolean;\n header?: string;\n showStatusBar?: boolean;\n interactive?: boolean;\n};\n"],"names":["LineType","stdout","stderr"],"mappings":";;;;+BAcaA;;;eAAAA;;;AAAN,IAAMA,WAAW;IACtBC,QAAQ;IACRC,QAAQ;AACV"}
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
-
import { Box,
|
|
2
|
+
import { Box, Text, useApp, useInput, useStdin } from 'ink';
|
|
3
3
|
import { useEffect, useSyncExternalStore } from 'react';
|
|
4
|
+
import { EXPANDED_MAX_VISIBLE_LINES } from '../constants.js';
|
|
4
5
|
import { processStore } from '../state/processStore.js';
|
|
5
6
|
import CompactProcessLine from './CompactProcessLine.js';
|
|
6
7
|
import Divider from './Divider.js';
|
|
7
8
|
import ErrorDetailModal from './ErrorDetailModal.js';
|
|
8
9
|
import ErrorListModal from './ErrorListModal.js';
|
|
10
|
+
import ExpandedOutput from './ExpandedOutput.js';
|
|
9
11
|
import StatusBar from './StatusBar.js';
|
|
10
12
|
export default function App() {
|
|
11
13
|
const { exit } = useApp();
|
|
@@ -14,15 +16,21 @@ export default function App() {
|
|
|
14
16
|
const processes = useSyncExternalStore(processStore.subscribe, processStore.getSnapshot);
|
|
15
17
|
const shouldExit = useSyncExternalStore(processStore.subscribe, processStore.getShouldExit);
|
|
16
18
|
const mode = useSyncExternalStore(processStore.subscribe, processStore.getMode);
|
|
19
|
+
const selectedIndex = useSyncExternalStore(processStore.subscribe, processStore.getSelectedIndex);
|
|
17
20
|
const selectedErrorIndex = useSyncExternalStore(processStore.subscribe, processStore.getSelectedErrorIndex);
|
|
18
|
-
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
+
const expandedId = useSyncExternalStore(processStore.subscribe, processStore.getExpandedId);
|
|
22
|
+
const scrollOffset = useSyncExternalStore(processStore.subscribe, processStore.getScrollOffset);
|
|
23
|
+
// Subscribed state that triggers re-renders
|
|
24
|
+
const header = useSyncExternalStore(processStore.subscribe, processStore.getHeader);
|
|
25
|
+
const showStatusBar = useSyncExternalStore(processStore.subscribe, processStore.getShowStatusBar);
|
|
26
|
+
const isInteractive = useSyncExternalStore(processStore.subscribe, processStore.getIsInteractive);
|
|
27
|
+
// Derived state (computed from processes which is already subscribed)
|
|
21
28
|
const failedProcesses = processStore.getFailedProcesses();
|
|
22
29
|
const runningCount = processStore.getRunningCount();
|
|
23
30
|
const doneCount = processStore.getDoneCount();
|
|
24
31
|
const errorCount = processStore.getErrorCount();
|
|
25
32
|
const errorLineCount = processStore.getErrorLineCount();
|
|
33
|
+
const isAllComplete = processStore.isAllComplete();
|
|
26
34
|
// Handle exit signal
|
|
27
35
|
useEffect(()=>{
|
|
28
36
|
if (shouldExit) {
|
|
@@ -32,15 +40,61 @@ export default function App() {
|
|
|
32
40
|
shouldExit,
|
|
33
41
|
exit
|
|
34
42
|
]);
|
|
43
|
+
// Auto-enter interactive mode when all complete and interactive flag is set
|
|
44
|
+
useEffect(()=>{
|
|
45
|
+
if (isAllComplete && isInteractive && mode === 'normal') {
|
|
46
|
+
processStore.setMode('interactive');
|
|
47
|
+
}
|
|
48
|
+
}, [
|
|
49
|
+
isAllComplete,
|
|
50
|
+
isInteractive,
|
|
51
|
+
mode
|
|
52
|
+
]);
|
|
35
53
|
// Keyboard handling (only active when raw mode is supported)
|
|
36
54
|
useInput((input, key)=>{
|
|
37
55
|
if (mode === 'normal') {
|
|
38
56
|
if (input === 'e' && errorCount > 0) {
|
|
39
57
|
processStore.setMode('errorList');
|
|
40
58
|
}
|
|
59
|
+
} else if (mode === 'interactive') {
|
|
60
|
+
if (input === 'q' || key.escape) {
|
|
61
|
+
if (expandedId) {
|
|
62
|
+
processStore.collapse();
|
|
63
|
+
} else {
|
|
64
|
+
processStore.signalExit(()=>{});
|
|
65
|
+
}
|
|
66
|
+
} else if (key.return) {
|
|
67
|
+
processStore.toggleExpand();
|
|
68
|
+
} else if (key.downArrow) {
|
|
69
|
+
if (expandedId) {
|
|
70
|
+
processStore.scrollDown(EXPANDED_MAX_VISIBLE_LINES);
|
|
71
|
+
} else {
|
|
72
|
+
processStore.selectNext();
|
|
73
|
+
}
|
|
74
|
+
} else if (key.upArrow) {
|
|
75
|
+
if (expandedId) {
|
|
76
|
+
processStore.scrollUp();
|
|
77
|
+
} else {
|
|
78
|
+
processStore.selectPrev();
|
|
79
|
+
}
|
|
80
|
+
} else if (input === 'j') {
|
|
81
|
+
if (expandedId) {
|
|
82
|
+
processStore.scrollDown(EXPANDED_MAX_VISIBLE_LINES);
|
|
83
|
+
} else {
|
|
84
|
+
processStore.selectNext();
|
|
85
|
+
}
|
|
86
|
+
} else if (input === 'k') {
|
|
87
|
+
if (expandedId) {
|
|
88
|
+
processStore.scrollUp();
|
|
89
|
+
} else {
|
|
90
|
+
processStore.selectPrev();
|
|
91
|
+
}
|
|
92
|
+
} else if (input === 'e' && errorCount > 0) {
|
|
93
|
+
processStore.setMode('errorList');
|
|
94
|
+
}
|
|
41
95
|
} else if (mode === 'errorList') {
|
|
42
96
|
if (key.escape) {
|
|
43
|
-
processStore.setMode('normal');
|
|
97
|
+
processStore.setMode(isInteractive ? 'interactive' : 'normal');
|
|
44
98
|
} else if (key.downArrow) {
|
|
45
99
|
processStore.selectNextError();
|
|
46
100
|
} else if (key.upArrow) {
|
|
@@ -81,21 +135,29 @@ export default function App() {
|
|
|
81
135
|
// Fallback if no error selected
|
|
82
136
|
processStore.setMode('errorList');
|
|
83
137
|
}
|
|
84
|
-
// Normal view
|
|
138
|
+
// Normal/Interactive view - render in original registration order
|
|
139
|
+
const showSelection = mode === 'interactive';
|
|
85
140
|
return /*#__PURE__*/ _jsxs(Box, {
|
|
86
141
|
flexDirection: "column",
|
|
87
142
|
children: [
|
|
88
|
-
/*#__PURE__*/ _jsx(
|
|
89
|
-
|
|
90
|
-
children: (item)=>/*#__PURE__*/ _jsx(CompactProcessLine, {
|
|
91
|
-
item: item
|
|
92
|
-
}, item.id)
|
|
143
|
+
/*#__PURE__*/ _jsx(Text, {
|
|
144
|
+
children: header || '(loading...)'
|
|
93
145
|
}),
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
146
|
+
/*#__PURE__*/ _jsx(Divider, {}),
|
|
147
|
+
processes.map((item, index)=>/*#__PURE__*/ _jsxs(Box, {
|
|
148
|
+
flexDirection: "column",
|
|
149
|
+
children: [
|
|
150
|
+
/*#__PURE__*/ _jsx(CompactProcessLine, {
|
|
151
|
+
item: item,
|
|
152
|
+
isSelected: showSelection && index === selectedIndex
|
|
153
|
+
}),
|
|
154
|
+
expandedId === item.id && /*#__PURE__*/ _jsx(ExpandedOutput, {
|
|
155
|
+
lines: item.lines,
|
|
156
|
+
scrollOffset: scrollOffset
|
|
157
|
+
})
|
|
158
|
+
]
|
|
97
159
|
}, item.id)),
|
|
98
|
-
processes.length > 0 && /*#__PURE__*/ _jsxs(_Fragment, {
|
|
160
|
+
showStatusBar && processes.length > 0 && /*#__PURE__*/ _jsxs(_Fragment, {
|
|
99
161
|
children: [
|
|
100
162
|
/*#__PURE__*/ _jsx(Divider, {}),
|
|
101
163
|
/*#__PURE__*/ _jsx(StatusBar, {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/node/spawn-term/src/components/App.tsx"],"sourcesContent":["import { Box, Static, useApp, useInput, useStdin } from 'ink';\nimport { useEffect, useSyncExternalStore } from 'react';\nimport { processStore } from '../state/processStore.ts';\nimport CompactProcessLine from './CompactProcessLine.ts';\nimport Divider from './Divider.ts';\nimport ErrorDetailModal from './ErrorDetailModal.ts';\nimport ErrorListModal from './ErrorListModal.ts';\nimport StatusBar from './StatusBar.ts';\n\nexport default function App(): React.JSX.Element {\n const { exit } = useApp();\n const { isRawModeSupported } = useStdin();\n\n // Subscribe to store state\n const processes = useSyncExternalStore(processStore.subscribe, processStore.getSnapshot);\n const shouldExit = useSyncExternalStore(processStore.subscribe, processStore.getShouldExit);\n const mode = useSyncExternalStore(processStore.subscribe, processStore.getMode);\n const selectedErrorIndex = useSyncExternalStore(processStore.subscribe, processStore.getSelectedErrorIndex);\n\n // Derived state\n const completedProcesses = processStore.getCompletedProcesses();\n const runningProcesses = processStore.getRunningProcesses();\n const failedProcesses = processStore.getFailedProcesses();\n const runningCount = processStore.getRunningCount();\n const doneCount = processStore.getDoneCount();\n const errorCount = processStore.getErrorCount();\n const errorLineCount = processStore.getErrorLineCount();\n\n // Handle exit signal\n useEffect(() => {\n if (shouldExit) {\n exit();\n }\n }, [shouldExit, exit]);\n\n // Keyboard handling (only active when raw mode is supported)\n useInput(\n (input, key) => {\n if (mode === 'normal') {\n if (input === 'e' && errorCount > 0) {\n processStore.setMode('errorList');\n }\n } else if (mode === 'errorList') {\n if (key.escape) {\n processStore.setMode('normal');\n } else if (key.downArrow) {\n processStore.selectNextError();\n } else if (key.upArrow) {\n processStore.selectPrevError();\n } else if (key.return) {\n processStore.setMode('errorDetail');\n }\n } else if (mode === 'errorDetail') {\n if (key.escape) {\n processStore.setMode('errorList');\n } else if (key.downArrow) {\n processStore.selectNextError();\n } else if (key.upArrow) {\n processStore.selectPrevError();\n }\n }\n },\n { isActive: isRawModeSupported === true }\n );\n\n // Error list modal\n if (mode === 'errorList') {\n return <ErrorListModal errors={failedProcesses} selectedIndex={selectedErrorIndex} totalErrorLines={errorLineCount} />;\n }\n\n // Error detail modal\n if (mode === 'errorDetail') {\n const selectedError = processStore.getSelectedError();\n if (selectedError) {\n return <ErrorDetailModal error={selectedError} currentIndex={selectedErrorIndex} totalErrors={failedProcesses.length} />;\n }\n // Fallback if no error selected\n processStore.setMode('errorList');\n }\n\n // Normal view\n return (\n <Box flexDirection=\"column\">\n {/* Static area - completed processes (completion order) */}\n <Static items={completedProcesses}>{(item) => <CompactProcessLine key={item.id} item={item} />}</Static>\n\n {/* Divider between completed and running */}\n {completedProcesses.length > 0 && runningProcesses.length > 0 && <Divider />}\n\n {/* Dynamic area - running processes */}\n {runningProcesses.map((item) => (\n <CompactProcessLine key={item.id} item={item} />\n ))}\n\n {/* Status bar */}\n {processes.length > 0 && (\n <>\n <Divider />\n <StatusBar running={runningCount} done={doneCount} errors={errorCount} errorLines={errorLineCount} />\n </>\n )}\n </Box>\n );\n}\n"],"names":["Box","Static","useApp","useInput","useStdin","useEffect","useSyncExternalStore","processStore","CompactProcessLine","Divider","ErrorDetailModal","ErrorListModal","StatusBar","App","exit","isRawModeSupported","processes","subscribe","getSnapshot","shouldExit","getShouldExit","mode","getMode","selectedErrorIndex","getSelectedErrorIndex","completedProcesses","getCompletedProcesses","runningProcesses","getRunningProcesses","failedProcesses","getFailedProcesses","runningCount","getRunningCount","doneCount","getDoneCount","errorCount","getErrorCount","errorLineCount","getErrorLineCount","input","key","setMode","escape","downArrow","selectNextError","upArrow","selectPrevError","return","isActive","errors","selectedIndex","totalErrorLines","selectedError","getSelectedError","error","currentIndex","totalErrors","length","flexDirection","items","item","id","map","running","done","errorLines"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/node/spawn-term/src/components/App.tsx"],"sourcesContent":["import { Box, Text, useApp, useInput, useStdin } from 'ink';\nimport { useEffect, useSyncExternalStore } from 'react';\nimport { EXPANDED_MAX_VISIBLE_LINES } from '../constants.ts';\nimport { processStore } from '../state/processStore.ts';\nimport CompactProcessLine from './CompactProcessLine.ts';\nimport Divider from './Divider.ts';\nimport ErrorDetailModal from './ErrorDetailModal.ts';\nimport ErrorListModal from './ErrorListModal.ts';\nimport ExpandedOutput from './ExpandedOutput.ts';\nimport StatusBar from './StatusBar.ts';\n\nexport default function App(): React.JSX.Element {\n const { exit } = useApp();\n const { isRawModeSupported } = useStdin();\n\n // Subscribe to store state\n const processes = useSyncExternalStore(processStore.subscribe, processStore.getSnapshot);\n const shouldExit = useSyncExternalStore(processStore.subscribe, processStore.getShouldExit);\n const mode = useSyncExternalStore(processStore.subscribe, processStore.getMode);\n const selectedIndex = useSyncExternalStore(processStore.subscribe, processStore.getSelectedIndex);\n const selectedErrorIndex = useSyncExternalStore(processStore.subscribe, processStore.getSelectedErrorIndex);\n const expandedId = useSyncExternalStore(processStore.subscribe, processStore.getExpandedId);\n const scrollOffset = useSyncExternalStore(processStore.subscribe, processStore.getScrollOffset);\n\n // Subscribed state that triggers re-renders\n const header = useSyncExternalStore(processStore.subscribe, processStore.getHeader);\n const showStatusBar = useSyncExternalStore(processStore.subscribe, processStore.getShowStatusBar);\n const isInteractive = useSyncExternalStore(processStore.subscribe, processStore.getIsInteractive);\n\n // Derived state (computed from processes which is already subscribed)\n const failedProcesses = processStore.getFailedProcesses();\n const runningCount = processStore.getRunningCount();\n const doneCount = processStore.getDoneCount();\n const errorCount = processStore.getErrorCount();\n const errorLineCount = processStore.getErrorLineCount();\n const isAllComplete = processStore.isAllComplete();\n\n // Handle exit signal\n useEffect(() => {\n if (shouldExit) {\n exit();\n }\n }, [shouldExit, exit]);\n\n // Auto-enter interactive mode when all complete and interactive flag is set\n useEffect(() => {\n if (isAllComplete && isInteractive && mode === 'normal') {\n processStore.setMode('interactive');\n }\n }, [isAllComplete, isInteractive, mode]);\n\n // Keyboard handling (only active when raw mode is supported)\n useInput(\n (input, key) => {\n if (mode === 'normal') {\n if (input === 'e' && errorCount > 0) {\n processStore.setMode('errorList');\n }\n } else if (mode === 'interactive') {\n if (input === 'q' || key.escape) {\n if (expandedId) {\n processStore.collapse();\n } else {\n processStore.signalExit(() => {});\n }\n } else if (key.return) {\n processStore.toggleExpand();\n } else if (key.downArrow) {\n if (expandedId) {\n processStore.scrollDown(EXPANDED_MAX_VISIBLE_LINES);\n } else {\n processStore.selectNext();\n }\n } else if (key.upArrow) {\n if (expandedId) {\n processStore.scrollUp();\n } else {\n processStore.selectPrev();\n }\n } else if (input === 'j') {\n if (expandedId) {\n processStore.scrollDown(EXPANDED_MAX_VISIBLE_LINES);\n } else {\n processStore.selectNext();\n }\n } else if (input === 'k') {\n if (expandedId) {\n processStore.scrollUp();\n } else {\n processStore.selectPrev();\n }\n } else if (input === 'e' && errorCount > 0) {\n processStore.setMode('errorList');\n }\n } else if (mode === 'errorList') {\n if (key.escape) {\n processStore.setMode(isInteractive ? 'interactive' : 'normal');\n } else if (key.downArrow) {\n processStore.selectNextError();\n } else if (key.upArrow) {\n processStore.selectPrevError();\n } else if (key.return) {\n processStore.setMode('errorDetail');\n }\n } else if (mode === 'errorDetail') {\n if (key.escape) {\n processStore.setMode('errorList');\n } else if (key.downArrow) {\n processStore.selectNextError();\n } else if (key.upArrow) {\n processStore.selectPrevError();\n }\n }\n },\n { isActive: isRawModeSupported === true }\n );\n\n // Error list modal\n if (mode === 'errorList') {\n return <ErrorListModal errors={failedProcesses} selectedIndex={selectedErrorIndex} totalErrorLines={errorLineCount} />;\n }\n\n // Error detail modal\n if (mode === 'errorDetail') {\n const selectedError = processStore.getSelectedError();\n if (selectedError) {\n return <ErrorDetailModal error={selectedError} currentIndex={selectedErrorIndex} totalErrors={failedProcesses.length} />;\n }\n // Fallback if no error selected\n processStore.setMode('errorList');\n }\n\n // Normal/Interactive view - render in original registration order\n const showSelection = mode === 'interactive';\n return (\n <Box flexDirection=\"column\">\n {/* Header - always render a line */}\n <Text>{header || '(loading...)'}</Text>\n <Divider />\n\n {/* All processes in registration order */}\n {processes.map((item, index) => (\n <Box key={item.id} flexDirection=\"column\">\n <CompactProcessLine item={item} isSelected={showSelection && index === selectedIndex} />\n {expandedId === item.id && <ExpandedOutput lines={item.lines} scrollOffset={scrollOffset} />}\n </Box>\n ))}\n\n {/* Status bar */}\n {showStatusBar && processes.length > 0 && (\n <>\n <Divider />\n <StatusBar running={runningCount} done={doneCount} errors={errorCount} errorLines={errorLineCount} />\n </>\n )}\n </Box>\n );\n}\n"],"names":["Box","Text","useApp","useInput","useStdin","useEffect","useSyncExternalStore","EXPANDED_MAX_VISIBLE_LINES","processStore","CompactProcessLine","Divider","ErrorDetailModal","ErrorListModal","ExpandedOutput","StatusBar","App","exit","isRawModeSupported","processes","subscribe","getSnapshot","shouldExit","getShouldExit","mode","getMode","selectedIndex","getSelectedIndex","selectedErrorIndex","getSelectedErrorIndex","expandedId","getExpandedId","scrollOffset","getScrollOffset","header","getHeader","showStatusBar","getShowStatusBar","isInteractive","getIsInteractive","failedProcesses","getFailedProcesses","runningCount","getRunningCount","doneCount","getDoneCount","errorCount","getErrorCount","errorLineCount","getErrorLineCount","isAllComplete","setMode","input","key","escape","collapse","signalExit","return","toggleExpand","downArrow","scrollDown","selectNext","upArrow","scrollUp","selectPrev","selectNextError","selectPrevError","isActive","errors","totalErrorLines","selectedError","getSelectedError","error","currentIndex","totalErrors","length","showSelection","flexDirection","map","item","index","isSelected","id","lines","running","done","errorLines"],"mappings":"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"}
|
|
@@ -30,6 +30,8 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
30
30
|
import { Box, Text, useStdout } from 'ink';
|
|
31
31
|
import { memo, useMemo } from 'react';
|
|
32
32
|
import figures from '../lib/figures.js';
|
|
33
|
+
import { calculateColumnWidth } from '../lib/format.js';
|
|
34
|
+
import { processStore } from '../state/processStore.js';
|
|
33
35
|
import { LineType } from '../types.js';
|
|
34
36
|
import Spinner from './Spinner.js';
|
|
35
37
|
// From: https://github.com/sindresorhus/cli-spinners/blob/00de8fbeee16fa49502fa4f687449f70f2c8ca2c/spinners.json#L2
|
|
@@ -63,15 +65,17 @@ function getLastOutputLine(lines) {
|
|
|
63
65
|
function getErrorCount(lines) {
|
|
64
66
|
return lines.filter((line)=>line.type === LineType.stderr).length;
|
|
65
67
|
}
|
|
66
|
-
export default /*#__PURE__*/ memo(function CompactProcessLine({ item }) {
|
|
68
|
+
export default /*#__PURE__*/ memo(function CompactProcessLine({ item, isSelected = false }) {
|
|
67
69
|
const { stdout } = useStdout();
|
|
68
70
|
const terminalWidth = (stdout === null || stdout === void 0 ? void 0 : stdout.columns) || 80;
|
|
69
71
|
const { group, title, state, lines } = item;
|
|
72
|
+
const selectionIndicator = isSelected ? figures.pointer : ' ';
|
|
70
73
|
// Display name: prefer group, fall back to title
|
|
71
74
|
const displayName = group || title;
|
|
72
|
-
// Calculate widths - use
|
|
75
|
+
// Calculate widths - use dynamic column width based on longest name
|
|
73
76
|
const iconWidth = 2; // icon + space
|
|
74
|
-
const
|
|
77
|
+
const maxGroupLength = processStore.getMaxGroupLength();
|
|
78
|
+
const nameColumnWidth = calculateColumnWidth('max', terminalWidth, maxGroupLength);
|
|
75
79
|
const gap = 1; // space between name and status
|
|
76
80
|
const statusWidth = terminalWidth - iconWidth - nameColumnWidth - gap;
|
|
77
81
|
// Truncate name if needed and pad to column width
|
|
@@ -115,11 +119,16 @@ export default /*#__PURE__*/ memo(function CompactProcessLine({ item }) {
|
|
|
115
119
|
const statusColor = state === 'error' ? 'red' : 'gray';
|
|
116
120
|
return /*#__PURE__*/ _jsxs(Box, {
|
|
117
121
|
children: [
|
|
122
|
+
/*#__PURE__*/ _jsx(Text, {
|
|
123
|
+
color: isSelected ? 'cyan' : undefined,
|
|
124
|
+
children: selectionIndicator
|
|
125
|
+
}),
|
|
118
126
|
/*#__PURE__*/ _jsx(Box, {
|
|
119
127
|
width: iconWidth,
|
|
120
128
|
children: icon
|
|
121
129
|
}),
|
|
122
130
|
/*#__PURE__*/ _jsx(Text, {
|
|
131
|
+
inverse: isSelected,
|
|
123
132
|
children: truncatedName
|
|
124
133
|
}),
|
|
125
134
|
statusText && /*#__PURE__*/ _jsxs(Text, {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/node/spawn-term/src/components/CompactProcessLine.tsx"],"sourcesContent":["import { Box, Text, useStdout } from 'ink';\nimport { memo, useMemo } from 'react';\nimport figures from '../lib/figures.ts';\nimport type { ChildProcess, Line } from '../types.ts';\nimport { LineType } from '../types.ts';\nimport Spinner from './Spinner.ts';\n\n// From: https://github.com/sindresorhus/cli-spinners/blob/00de8fbeee16fa49502fa4f687449f70f2c8ca2c/spinners.json#L2\nconst SPINNER = {\n interval: 80,\n frames: ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'],\n};\n\ntype Props = {\n item: ChildProcess;\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 getLastOutputLine(lines: Line[]): string {\n for (let i = lines.length - 1; i >= 0; i--) {\n if (lines[i].text.length > 0) {\n return lines[i].text;\n }\n }\n return '';\n}\n\nfunction getErrorCount(lines: Line[]): number {\n return lines.filter((line) => line.type === LineType.stderr).length;\n}\n\nexport default memo(function CompactProcessLine({ item }: Props) {\n const { stdout } = useStdout();\n const terminalWidth = stdout?.columns || 80;\n\n const { group, title, state, lines } = item;\n\n // Display name: prefer group, fall back to title\n const displayName = group || title;\n\n // Calculate widths - use
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/node/spawn-term/src/components/CompactProcessLine.tsx"],"sourcesContent":["import { Box, Text, useStdout } from 'ink';\nimport { memo, useMemo } from 'react';\nimport figures from '../lib/figures.ts';\nimport { calculateColumnWidth } from '../lib/format.ts';\nimport { processStore } from '../state/processStore.ts';\nimport type { ChildProcess, Line } from '../types.ts';\nimport { LineType } from '../types.ts';\nimport Spinner from './Spinner.ts';\n\n// From: https://github.com/sindresorhus/cli-spinners/blob/00de8fbeee16fa49502fa4f687449f70f2c8ca2c/spinners.json#L2\nconst SPINNER = {\n interval: 80,\n frames: ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'],\n};\n\ntype Props = {\n item: ChildProcess;\n isSelected?: boolean;\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 getLastOutputLine(lines: Line[]): string {\n for (let i = lines.length - 1; i >= 0; i--) {\n if (lines[i].text.length > 0) {\n return lines[i].text;\n }\n }\n return '';\n}\n\nfunction getErrorCount(lines: Line[]): number {\n return lines.filter((line) => line.type === LineType.stderr).length;\n}\n\nexport default memo(function CompactProcessLine({ item, isSelected = false }: Props) {\n const { stdout } = useStdout();\n const terminalWidth = stdout?.columns || 80;\n\n const { group, title, state, lines } = item;\n const selectionIndicator = isSelected ? figures.pointer : ' ';\n\n // Display name: prefer group, fall back to title\n const displayName = group || title;\n\n // Calculate widths - use dynamic column width based on longest name\n const iconWidth = 2; // icon + space\n const maxGroupLength = processStore.getMaxGroupLength();\n const nameColumnWidth = calculateColumnWidth('max', terminalWidth, maxGroupLength);\n const gap = 1; // space between name and status\n const statusWidth = terminalWidth - iconWidth - nameColumnWidth - gap;\n\n // Truncate name if needed and pad to column width\n const truncatedName = truncate(displayName, nameColumnWidth).padEnd(nameColumnWidth);\n\n // Status text based on state\n const statusText = useMemo(() => {\n if (state === 'running') {\n const lastLine = getLastOutputLine(lines);\n return lastLine ? truncate(lastLine, statusWidth) : '';\n }\n if (state === 'error') {\n const errorCount = getErrorCount(lines);\n return errorCount > 0 ? `${errorCount} error${errorCount > 1 ? 's' : ''}` : 'failed';\n }\n return ''; // success - no status text\n }, [state, lines, statusWidth]);\n\n // Icon based on state\n const icon = useMemo(() => {\n switch (state) {\n case 'running':\n return <Spinner {...SPINNER} />;\n case 'success':\n return <Text color=\"green\">{figures.tick}</Text>;\n case 'error':\n return <Text color=\"red\">{figures.cross}</Text>;\n }\n }, [state]);\n\n // Status text color\n const statusColor = state === 'error' ? 'red' : 'gray';\n\n return (\n <Box>\n <Text color={isSelected ? 'cyan' : undefined}>{selectionIndicator}</Text>\n <Box width={iconWidth}>{icon}</Box>\n <Text inverse={isSelected}>{truncatedName}</Text>\n {statusText && <Text color={statusColor}> {statusText}</Text>}\n </Box>\n );\n});\n"],"names":["Box","Text","useStdout","memo","useMemo","figures","calculateColumnWidth","processStore","LineType","Spinner","SPINNER","interval","frames","truncate","str","maxLength","length","slice","getLastOutputLine","lines","i","text","getErrorCount","filter","line","type","stderr","CompactProcessLine","item","isSelected","stdout","terminalWidth","columns","group","title","state","selectionIndicator","pointer","displayName","iconWidth","maxGroupLength","getMaxGroupLength","nameColumnWidth","gap","statusWidth","truncatedName","padEnd","statusText","lastLine","errorCount","icon","color","tick","cross","statusColor","undefined","width","inverse"],"mappings":"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"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Box, Text } from 'ink';
|
|
3
|
+
import { memo } from 'react';
|
|
4
|
+
import { EXPANDED_MAX_VISIBLE_LINES } from '../constants.js';
|
|
5
|
+
import { LineType } from '../types.js';
|
|
6
|
+
export default /*#__PURE__*/ memo(function ExpandedOutput({ lines, scrollOffset, maxVisible = EXPANDED_MAX_VISIBLE_LINES }) {
|
|
7
|
+
const visibleLines = lines.slice(scrollOffset, scrollOffset + maxVisible);
|
|
8
|
+
const hasMore = lines.length > scrollOffset + maxVisible;
|
|
9
|
+
const remaining = lines.length - scrollOffset - maxVisible;
|
|
10
|
+
if (lines.length === 0) {
|
|
11
|
+
return /*#__PURE__*/ _jsx(Box, {
|
|
12
|
+
paddingLeft: 2,
|
|
13
|
+
children: /*#__PURE__*/ _jsx(Text, {
|
|
14
|
+
dimColor: true,
|
|
15
|
+
children: "│ (no output)"
|
|
16
|
+
})
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
return /*#__PURE__*/ _jsxs(Box, {
|
|
20
|
+
flexDirection: "column",
|
|
21
|
+
paddingLeft: 2,
|
|
22
|
+
children: [
|
|
23
|
+
visibleLines.map((line, i)=>// biome-ignore lint/suspicious/noArrayIndexKey: Lines have no unique ID, index is stable for this scrolling view
|
|
24
|
+
/*#__PURE__*/ _jsxs(Text, {
|
|
25
|
+
color: line.type === LineType.stderr ? 'red' : undefined,
|
|
26
|
+
children: [
|
|
27
|
+
"│ ",
|
|
28
|
+
line.text
|
|
29
|
+
]
|
|
30
|
+
}, scrollOffset + i)),
|
|
31
|
+
hasMore && /*#__PURE__*/ _jsxs(Text, {
|
|
32
|
+
dimColor: true,
|
|
33
|
+
children: [
|
|
34
|
+
"│ [+",
|
|
35
|
+
remaining,
|
|
36
|
+
" more, j/k to scroll]"
|
|
37
|
+
]
|
|
38
|
+
})
|
|
39
|
+
]
|
|
40
|
+
});
|
|
41
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/node/spawn-term/src/components/ExpandedOutput.tsx"],"sourcesContent":["import { Box, Text } from 'ink';\nimport { memo } from 'react';\nimport { EXPANDED_MAX_VISIBLE_LINES } from '../constants.ts';\nimport type { Line } from '../types.ts';\nimport { LineType } from '../types.ts';\n\ntype Props = {\n lines: Line[];\n scrollOffset: number;\n maxVisible?: number;\n};\n\nexport default memo(function ExpandedOutput({ lines, scrollOffset, maxVisible = EXPANDED_MAX_VISIBLE_LINES }: Props) {\n const visibleLines = lines.slice(scrollOffset, scrollOffset + maxVisible);\n const hasMore = lines.length > scrollOffset + maxVisible;\n const remaining = lines.length - scrollOffset - maxVisible;\n\n if (lines.length === 0) {\n return (\n <Box paddingLeft={2}>\n <Text dimColor>│ (no output)</Text>\n </Box>\n );\n }\n\n return (\n <Box flexDirection=\"column\" paddingLeft={2}>\n {visibleLines.map((line, i) => (\n // biome-ignore lint/suspicious/noArrayIndexKey: Lines have no unique ID, index is stable for this scrolling view\n <Text key={scrollOffset + i} color={line.type === LineType.stderr ? 'red' : undefined}>\n │ {line.text}\n </Text>\n ))}\n {hasMore && <Text dimColor>│ [+{remaining} more, j/k to scroll]</Text>}\n </Box>\n );\n});\n"],"names":["Box","Text","memo","EXPANDED_MAX_VISIBLE_LINES","LineType","ExpandedOutput","lines","scrollOffset","maxVisible","visibleLines","slice","hasMore","length","remaining","paddingLeft","dimColor","flexDirection","map","line","i","color","type","stderr","undefined","text"],"mappings":";AAAA,SAASA,GAAG,EAAEC,IAAI,QAAQ,MAAM;AAChC,SAASC,IAAI,QAAQ,QAAQ;AAC7B,SAASC,0BAA0B,QAAQ,kBAAkB;AAE7D,SAASC,QAAQ,QAAQ,cAAc;AAQvC,6BAAeF,KAAK,SAASG,eAAe,EAAEC,KAAK,EAAEC,YAAY,EAAEC,aAAaL,0BAA0B,EAAS;IACjH,MAAMM,eAAeH,MAAMI,KAAK,CAACH,cAAcA,eAAeC;IAC9D,MAAMG,UAAUL,MAAMM,MAAM,GAAGL,eAAeC;IAC9C,MAAMK,YAAYP,MAAMM,MAAM,GAAGL,eAAeC;IAEhD,IAAIF,MAAMM,MAAM,KAAK,GAAG;QACtB,qBACE,KAACZ;YAAIc,aAAa;sBAChB,cAAA,KAACb;gBAAKc,QAAQ;0BAAC;;;IAGrB;IAEA,qBACE,MAACf;QAAIgB,eAAc;QAASF,aAAa;;YACtCL,aAAaQ,GAAG,CAAC,CAACC,MAAMC,IACvB,iHAAiH;8BACjH,MAAClB;oBAA4BmB,OAAOF,KAAKG,IAAI,KAAKjB,SAASkB,MAAM,GAAG,QAAQC;;wBAAW;wBAClFL,KAAKM,IAAI;;mBADHjB,eAAeY;YAI3BR,yBAAW,MAACV;gBAAKc,QAAQ;;oBAAC;oBAAKF;oBAAU;;;;;AAGhD,GAAG"}
|