spawn-term 3.1.3 → 3.1.5
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 +58 -19
- package/dist/cjs/components/App.js.map +1 -1
- package/dist/cjs/components/ErrorFooter.js +2 -10
- package/dist/cjs/components/ErrorFooter.js.map +1 -1
- package/dist/cjs/index-cjs.js.map +1 -1
- package/dist/cjs/index-esm.js.map +1 -1
- package/dist/cjs/src/index-cjs.d.ts +1 -0
- package/dist/cjs/src/index-esm.d.ts +1 -0
- package/dist/cjs/src/state/Navigator.d.ts +27 -0
- package/dist/cjs/src/state/processStore.d.ts +28 -25
- package/dist/cjs/src/types.d.ts +3 -0
- package/dist/cjs/state/Navigator.js +127 -0
- package/dist/cjs/state/Navigator.js.map +1 -0
- package/dist/cjs/state/processStore.js +191 -105
- package/dist/cjs/state/processStore.js.map +1 -1
- package/dist/cjs/types.js.map +1 -1
- package/dist/esm/components/App.js +58 -19
- package/dist/esm/components/App.js.map +1 -1
- package/dist/esm/components/ErrorFooter.js +2 -10
- package/dist/esm/components/ErrorFooter.js.map +1 -1
- package/dist/esm/index-cjs.js.map +1 -1
- package/dist/esm/index-esm.js.map +1 -1
- package/dist/esm/src/index-cjs.d.ts +1 -0
- package/dist/esm/src/index-esm.d.ts +1 -0
- package/dist/esm/src/state/Navigator.d.ts +27 -0
- package/dist/esm/src/state/processStore.d.ts +28 -25
- package/dist/esm/src/types.d.ts +3 -0
- package/dist/esm/state/Navigator.js +114 -0
- package/dist/esm/state/Navigator.js.map +1 -0
- package/dist/esm/state/processStore.js +156 -100
- package/dist/esm/state/processStore.js.map +1 -1
- package/dist/esm/types.js.map +1 -1
- package/package.json +4 -4
|
@@ -1,12 +1,28 @@
|
|
|
1
1
|
import { arrayFind } from '../compat.js';
|
|
2
2
|
import { DEFAULT_COLUMN_WIDTH } from '../constants.js';
|
|
3
3
|
import { LineType } from '../types.js';
|
|
4
|
+
import { createNavigator } from './Navigator.js';
|
|
4
5
|
export class ProcessStore {
|
|
5
|
-
|
|
6
|
+
getErrorLines() {
|
|
7
|
+
return this.getFailedProcesses().map((p)=>({
|
|
8
|
+
processName: p.group || p.title,
|
|
9
|
+
lines: this.getProcessLines(p.id)
|
|
10
|
+
}));
|
|
11
|
+
}
|
|
12
|
+
// === DATA: Mutations ===
|
|
6
13
|
addProcess(process) {
|
|
14
|
+
// Create scroll navigator for this process
|
|
15
|
+
const processWithNav = {
|
|
16
|
+
...process,
|
|
17
|
+
scrollNav: createNavigator({
|
|
18
|
+
getLength: ()=>this.getProcessLineCount(processWithNav.id),
|
|
19
|
+
wrap: false,
|
|
20
|
+
onMove: ()=>this.notify()
|
|
21
|
+
})
|
|
22
|
+
};
|
|
7
23
|
this.processes = [
|
|
8
24
|
...this.processes,
|
|
9
|
-
|
|
25
|
+
processWithNav
|
|
10
26
|
];
|
|
11
27
|
this.notify();
|
|
12
28
|
}
|
|
@@ -63,42 +79,16 @@ export class ProcessStore {
|
|
|
63
79
|
}
|
|
64
80
|
return process.lines.length;
|
|
65
81
|
}
|
|
66
|
-
//
|
|
82
|
+
// === VIEW STATE: Mutations ===
|
|
67
83
|
setMode(mode) {
|
|
68
84
|
this.mode = mode;
|
|
69
85
|
if (mode === 'interactive') {
|
|
70
|
-
this.
|
|
86
|
+
this.listNav.setPosition(0);
|
|
71
87
|
}
|
|
72
88
|
this.notify();
|
|
73
89
|
}
|
|
74
|
-
// Interactive mode navigation
|
|
75
|
-
selectNext(visibleCount) {
|
|
76
|
-
if (this.processes.length > 0) {
|
|
77
|
-
this.selectedIndex = (this.selectedIndex + 1) % this.processes.length;
|
|
78
|
-
this.adjustListScroll(visibleCount);
|
|
79
|
-
this.notify();
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
selectPrev(visibleCount) {
|
|
83
|
-
if (this.processes.length > 0) {
|
|
84
|
-
this.selectedIndex = (this.selectedIndex - 1 + this.processes.length) % this.processes.length;
|
|
85
|
-
this.adjustListScroll(visibleCount);
|
|
86
|
-
this.notify();
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
adjustListScroll(visibleCount) {
|
|
90
|
-
if (!visibleCount || visibleCount <= 0) return;
|
|
91
|
-
// Ensure selected item is visible in viewport
|
|
92
|
-
if (this.selectedIndex < this.listScrollOffset) {
|
|
93
|
-
// Selected is above viewport - scroll up
|
|
94
|
-
this.listScrollOffset = this.selectedIndex;
|
|
95
|
-
} else if (this.selectedIndex >= this.listScrollOffset + visibleCount) {
|
|
96
|
-
// Selected is below viewport - scroll down
|
|
97
|
-
this.listScrollOffset = this.selectedIndex - visibleCount + 1;
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
90
|
getSelectedProcess() {
|
|
101
|
-
return this.processes[this.
|
|
91
|
+
return this.processes[this.listNav.position];
|
|
102
92
|
}
|
|
103
93
|
// Error footer methods (for non-interactive mode)
|
|
104
94
|
toggleErrorFooter() {
|
|
@@ -111,82 +101,138 @@ export class ProcessStore {
|
|
|
111
101
|
this.notify();
|
|
112
102
|
}
|
|
113
103
|
}
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
104
|
+
// === NAVIGATION: List (delegates to listNav) ===
|
|
105
|
+
selectNext(visibleCount) {
|
|
106
|
+
this.listNav.down();
|
|
107
|
+
if (visibleCount) {
|
|
108
|
+
this.listNav.ensureVisible(visibleCount);
|
|
109
|
+
}
|
|
119
110
|
}
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
if (this.expandedId === selected.id) {
|
|
125
|
-
// Collapse
|
|
126
|
-
this.expandedId = null;
|
|
127
|
-
this.scrollOffset = 0;
|
|
128
|
-
} else {
|
|
129
|
-
// Expand
|
|
130
|
-
this.expandedId = selected.id;
|
|
131
|
-
this.scrollOffset = 0;
|
|
111
|
+
selectPrev(visibleCount) {
|
|
112
|
+
this.listNav.up();
|
|
113
|
+
if (visibleCount) {
|
|
114
|
+
this.listNav.ensureVisible(visibleCount);
|
|
132
115
|
}
|
|
133
|
-
this.notify();
|
|
134
116
|
}
|
|
135
|
-
|
|
136
|
-
this.
|
|
137
|
-
|
|
138
|
-
|
|
117
|
+
selectPageDown(pageSize, visibleCount) {
|
|
118
|
+
this.listNav.pageDown(pageSize, visibleCount);
|
|
119
|
+
}
|
|
120
|
+
selectPageUp(pageSize, visibleCount) {
|
|
121
|
+
this.listNav.pageUp(pageSize, visibleCount);
|
|
122
|
+
}
|
|
123
|
+
selectFirst(visibleCount) {
|
|
124
|
+
this.listNav.toStart();
|
|
125
|
+
if (visibleCount) {
|
|
126
|
+
this.listNav.ensureVisible(visibleCount);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
selectLast(visibleCount) {
|
|
130
|
+
this.listNav.toEnd();
|
|
131
|
+
if (visibleCount) {
|
|
132
|
+
this.listNav.ensureVisible(visibleCount);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
clampListViewport(visibleCount) {
|
|
136
|
+
const changed = this.listNav.clampViewport(visibleCount);
|
|
137
|
+
if (changed) {
|
|
138
|
+
this.notify();
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
// === NAVIGATION: Expanded content (delegates to process.scrollNav) ===
|
|
142
|
+
getExpandedNav() {
|
|
143
|
+
var _this_getProcess;
|
|
144
|
+
if (!this.expandedId) return undefined;
|
|
145
|
+
const nav = (_this_getProcess = this.getProcess(this.expandedId)) === null || _this_getProcess === void 0 ? void 0 : _this_getProcess.scrollNav;
|
|
146
|
+
if (!nav) return undefined;
|
|
147
|
+
return {
|
|
148
|
+
nav,
|
|
149
|
+
id: this.expandedId
|
|
150
|
+
};
|
|
139
151
|
}
|
|
140
152
|
scrollDown(maxVisible) {
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
153
|
+
const expanded = this.getExpandedNav();
|
|
154
|
+
if (!expanded) return;
|
|
155
|
+
const lineCount = this.getProcessLineCount(expanded.id);
|
|
144
156
|
const maxOffset = Math.max(0, lineCount - maxVisible);
|
|
145
|
-
if
|
|
146
|
-
|
|
147
|
-
|
|
157
|
+
// Only scroll if not at bottom
|
|
158
|
+
if (expanded.nav.position < maxOffset) {
|
|
159
|
+
expanded.nav.down();
|
|
148
160
|
}
|
|
149
161
|
}
|
|
150
162
|
scrollUp() {
|
|
151
|
-
|
|
152
|
-
if (
|
|
153
|
-
|
|
154
|
-
|
|
163
|
+
const expanded = this.getExpandedNav();
|
|
164
|
+
if (!expanded) return;
|
|
165
|
+
if (expanded.nav.position > 0) {
|
|
166
|
+
expanded.nav.up();
|
|
155
167
|
}
|
|
156
168
|
}
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
if (!
|
|
160
|
-
const lineCount = this.getProcessLineCount(
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
169
|
+
scrollPageDown(pageSize) {
|
|
170
|
+
const expanded = this.getExpandedNav();
|
|
171
|
+
if (!expanded) return;
|
|
172
|
+
const lineCount = this.getProcessLineCount(expanded.id);
|
|
173
|
+
const maxOffset = Math.max(0, lineCount - pageSize);
|
|
174
|
+
// Clamp to max offset
|
|
175
|
+
const newPosition = Math.min(expanded.nav.position + pageSize, maxOffset);
|
|
176
|
+
expanded.nav.setPosition(newPosition);
|
|
164
177
|
this.notify();
|
|
165
178
|
}
|
|
166
|
-
scrollPageUp(
|
|
167
|
-
|
|
168
|
-
|
|
179
|
+
scrollPageUp(pageSize) {
|
|
180
|
+
const expanded = this.getExpandedNav();
|
|
181
|
+
if (!expanded) return;
|
|
182
|
+
const newPosition = Math.max(0, expanded.nav.position - pageSize);
|
|
183
|
+
expanded.nav.setPosition(newPosition);
|
|
169
184
|
this.notify();
|
|
170
185
|
}
|
|
171
|
-
// Jump to top/bottom
|
|
172
186
|
scrollToTop() {
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
187
|
+
const expanded = this.getExpandedNav();
|
|
188
|
+
if (!expanded) return;
|
|
189
|
+
expanded.nav.toStart();
|
|
176
190
|
}
|
|
177
191
|
scrollToBottom(maxVisible) {
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
192
|
+
const expanded = this.getExpandedNav();
|
|
193
|
+
if (!expanded) return;
|
|
194
|
+
const lineCount = this.getProcessLineCount(expanded.id);
|
|
195
|
+
const newPosition = Math.max(0, lineCount - maxVisible);
|
|
196
|
+
expanded.nav.setPosition(newPosition);
|
|
182
197
|
this.notify();
|
|
183
198
|
}
|
|
184
|
-
//
|
|
199
|
+
// === EXPANSION ===
|
|
200
|
+
toggleExpand(visibleCountWhenExpanded, visibleCountWhenCollapsed) {
|
|
201
|
+
const selected = this.getSelectedProcess();
|
|
202
|
+
if (!selected) return;
|
|
203
|
+
if (this.expandedId === selected.id) {
|
|
204
|
+
// Collapse (keep scroll position for later)
|
|
205
|
+
this.expandedId = null;
|
|
206
|
+
// Adjust viewport to avoid empty space at bottom
|
|
207
|
+
if (visibleCountWhenCollapsed) {
|
|
208
|
+
this.listNav.clampViewport(visibleCountWhenCollapsed);
|
|
209
|
+
}
|
|
210
|
+
} else {
|
|
211
|
+
// Expand (scroll position is preserved in process.scrollNav)
|
|
212
|
+
this.expandedId = selected.id;
|
|
213
|
+
// Adjust list scroll to keep expanded process visible
|
|
214
|
+
if (visibleCountWhenExpanded) {
|
|
215
|
+
this.listNav.ensureVisible(visibleCountWhenExpanded);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
this.notify();
|
|
219
|
+
}
|
|
220
|
+
collapse(visibleCountWhenCollapsed) {
|
|
221
|
+
// Collapse but keep scroll position in process
|
|
222
|
+
this.expandedId = null;
|
|
223
|
+
// Adjust viewport to avoid empty space at bottom
|
|
224
|
+
if (visibleCountWhenCollapsed) {
|
|
225
|
+
this.listNav.clampViewport(visibleCountWhenCollapsed);
|
|
226
|
+
}
|
|
227
|
+
this.notify();
|
|
228
|
+
}
|
|
229
|
+
// === EXIT ===
|
|
185
230
|
signalExit(callback) {
|
|
186
231
|
this.shouldExit = true;
|
|
187
232
|
this.exitCallback = callback;
|
|
188
233
|
this.notify();
|
|
189
234
|
}
|
|
235
|
+
// === RESET ===
|
|
190
236
|
reset() {
|
|
191
237
|
// Dispose terminal buffers before clearing
|
|
192
238
|
for (const process of this.processes){
|
|
@@ -198,14 +244,12 @@ export class ProcessStore {
|
|
|
198
244
|
this.shouldExit = false;
|
|
199
245
|
this.exitCallback = null;
|
|
200
246
|
this.mode = 'normal';
|
|
201
|
-
this.
|
|
247
|
+
this.listNav.reset();
|
|
202
248
|
this.expandedId = null;
|
|
203
|
-
this.scrollOffset = 0;
|
|
204
|
-
this.listScrollOffset = 0;
|
|
205
249
|
this.errorFooterExpanded = false;
|
|
206
250
|
this.header = undefined;
|
|
207
251
|
}
|
|
208
|
-
//
|
|
252
|
+
// === INFRASTRUCTURE ===
|
|
209
253
|
notify() {
|
|
210
254
|
this.bufferVersion++;
|
|
211
255
|
this.listeners.forEach((l)=>{
|
|
@@ -213,28 +257,27 @@ export class ProcessStore {
|
|
|
213
257
|
});
|
|
214
258
|
}
|
|
215
259
|
constructor(options = {}){
|
|
260
|
+
// === DATA: Process collection ===
|
|
216
261
|
this.processes = [];
|
|
217
262
|
this.completedIds = []; // Track completion order
|
|
218
|
-
|
|
219
|
-
this.shouldExit = false;
|
|
220
|
-
this.exitCallback = null;
|
|
221
|
-
// UI state
|
|
263
|
+
// === VIEW STATE ===
|
|
222
264
|
this.mode = 'normal';
|
|
223
|
-
this.selectedIndex = 0;
|
|
224
265
|
this.expandedId = null;
|
|
225
|
-
this.scrollOffset = 0;
|
|
226
|
-
this.listScrollOffset = 0; // Viewport offset for process list
|
|
227
266
|
this.errorFooterExpanded = false; // For non-interactive error footer
|
|
228
|
-
this.bufferVersion = 0; // Increments on every notify() to trigger re-renders
|
|
229
267
|
this.showStatusBar = false;
|
|
230
268
|
this.isInteractive = false;
|
|
231
|
-
//
|
|
269
|
+
// === INFRASTRUCTURE ===
|
|
270
|
+
this.listeners = new Set();
|
|
271
|
+
this.shouldExit = false;
|
|
272
|
+
this.exitCallback = null;
|
|
273
|
+
this.bufferVersion = 0; // Increments on every notify() to trigger re-renders
|
|
274
|
+
// === SUBSCRIPTION API (useSyncExternalStore) ===
|
|
232
275
|
this.subscribe = (listener)=>{
|
|
233
276
|
this.listeners.add(listener);
|
|
234
277
|
return ()=>this.listeners.delete(listener);
|
|
235
278
|
};
|
|
236
279
|
this.getSnapshot = ()=>this.processes;
|
|
237
|
-
//
|
|
280
|
+
// === DATA: Queries ===
|
|
238
281
|
this.getRunningProcesses = ()=>{
|
|
239
282
|
return this.processes.filter((p)=>p.state === 'running');
|
|
240
283
|
};
|
|
@@ -256,14 +299,21 @@ export class ProcessStore {
|
|
|
256
299
|
this.getErrorLineCount = ()=>{
|
|
257
300
|
return this.processes.filter((p)=>p.state === 'error').reduce((total, p)=>total + this.getProcessLineCount(p.id), 0);
|
|
258
301
|
};
|
|
259
|
-
//
|
|
302
|
+
// === VIEW STATE: Getters ===
|
|
260
303
|
this.getMode = ()=>this.mode;
|
|
261
|
-
this.getSelectedIndex = ()=>this.
|
|
304
|
+
this.getSelectedIndex = ()=>this.listNav.position;
|
|
262
305
|
this.getExpandedId = ()=>this.expandedId;
|
|
263
|
-
this.
|
|
264
|
-
this.getListScrollOffset = ()=>this.listScrollOffset;
|
|
306
|
+
this.getListScrollOffset = ()=>this.listNav.viewportOffset;
|
|
265
307
|
this.getErrorFooterExpanded = ()=>this.errorFooterExpanded;
|
|
266
308
|
this.getBufferVersion = ()=>this.bufferVersion;
|
|
309
|
+
// Get scroll offset for expanded process (or 0 if none)
|
|
310
|
+
this.getScrollOffset = ()=>{
|
|
311
|
+
var _process_scrollNav;
|
|
312
|
+
if (!this.expandedId) return 0;
|
|
313
|
+
const process = this.getProcess(this.expandedId);
|
|
314
|
+
var _process_scrollNav_position;
|
|
315
|
+
return (_process_scrollNav_position = process === null || process === void 0 ? void 0 : (_process_scrollNav = process.scrollNav) === null || _process_scrollNav === void 0 ? void 0 : _process_scrollNav.position) !== null && _process_scrollNav_position !== void 0 ? _process_scrollNav_position : 0;
|
|
316
|
+
};
|
|
267
317
|
// Session-level getters (set at session creation, immutable)
|
|
268
318
|
this.getHeader = ()=>this.header;
|
|
269
319
|
this.getShowStatusBar = ()=>this.showStatusBar;
|
|
@@ -276,5 +326,11 @@ export class ProcessStore {
|
|
|
276
326
|
this.showStatusBar = (_options_showStatusBar = options.showStatusBar) !== null && _options_showStatusBar !== void 0 ? _options_showStatusBar : false;
|
|
277
327
|
var _options_interactive;
|
|
278
328
|
this.isInteractive = (_options_interactive = options.interactive) !== null && _options_interactive !== void 0 ? _options_interactive : false;
|
|
329
|
+
// Create list navigator with wrap-around behavior
|
|
330
|
+
this.listNav = createNavigator({
|
|
331
|
+
getLength: ()=>this.processes.length,
|
|
332
|
+
wrap: true,
|
|
333
|
+
onMove: ()=>this.notify()
|
|
334
|
+
});
|
|
279
335
|
}
|
|
280
336
|
} // Note: No global singleton - session creates its own store instance
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/node/spawn-term/src/state/processStore.ts"],"sourcesContent":["import { arrayFind } from '../compat.ts';\nimport { DEFAULT_COLUMN_WIDTH } from '../constants.ts';\nimport type { ChildProcess, Line, SessionOptions } from '../types.ts';\nimport { LineType } from '../types.ts';\n\ntype Listener = () => void;\ntype Mode = 'normal' | 'interactive';\n\nexport class ProcessStore {\n private processes: ChildProcess[] = [];\n private completedIds: string[] = []; // Track completion order\n private listeners = new Set<Listener>();\n private shouldExit = false;\n private exitCallback: (() => void) | null = null;\n\n // UI state\n private mode: Mode = 'normal';\n private selectedIndex = 0;\n private expandedId: string | null = null;\n private scrollOffset = 0;\n private listScrollOffset = 0; // Viewport offset for process list\n private errorFooterExpanded = false; // For non-interactive error footer\n private bufferVersion = 0; // Increments on every notify() to trigger re-renders\n\n // Session-level display settings (set once at session creation)\n private header: string | undefined;\n private showStatusBar = false;\n private isInteractive = false;\n\n constructor(options: SessionOptions = {}) {\n this.header = options.header;\n this.showStatusBar = options.showStatusBar ?? false;\n this.isInteractive = options.interactive ?? false;\n }\n\n // useSyncExternalStore API\n subscribe = (listener: Listener): (() => void) => {\n this.listeners.add(listener);\n return () => this.listeners.delete(listener);\n };\n\n getSnapshot = (): ChildProcess[] => this.processes;\n\n // Filtered getters\n getRunningProcesses = (): ChildProcess[] => {\n return this.processes.filter((p) => p.state === 'running');\n };\n\n getCompletedProcesses = (): ChildProcess[] => {\n // Return in completion order\n return this.completedIds.map((id) => arrayFind(this.processes, (p) => p.id === id)).filter((p): p is ChildProcess => p !== undefined);\n };\n\n getFailedProcesses = (): ChildProcess[] => {\n return this.processes.filter((p) => p.state === 'error');\n };\n\n // Counts\n getRunningCount = (): number => this.processes.filter((p) => p.state === 'running').length;\n getMaxGroupLength = (): number => {\n if (this.processes.length === 0) return DEFAULT_COLUMN_WIDTH;\n return Math.max(...this.processes.map((p) => (p.group || p.title).length));\n };\n getDoneCount = (): number => this.processes.filter((p) => p.state !== 'running').length;\n getErrorCount = (): number => this.processes.filter((p) => p.state === 'error').length;\n getErrorLineCount = (): number => {\n return this.processes.filter((p) => p.state === 'error').reduce((total, p) => total + this.getProcessLineCount(p.id), 0);\n };\n\n // UI state getters\n getMode = (): Mode => this.mode;\n getSelectedIndex = (): number => this.selectedIndex;\n getExpandedId = (): string | null => this.expandedId;\n getScrollOffset = (): number => this.scrollOffset;\n getListScrollOffset = (): number => this.listScrollOffset;\n getErrorFooterExpanded = (): boolean => this.errorFooterExpanded;\n getBufferVersion = (): number => this.bufferVersion;\n // Session-level getters (set at session creation, immutable)\n getHeader = (): string | undefined => this.header;\n getShowStatusBar = (): boolean => this.showStatusBar;\n getIsInteractive = (): boolean => this.isInteractive;\n isAllComplete = (): boolean => this.processes.length > 0 && this.processes.every((p) => p.state !== 'running');\n\n // Mutations - Ink handles render throttling at 30 FPS\n addProcess(process: ChildProcess): void {\n this.processes = [...this.processes, process];\n this.notify();\n }\n\n updateProcess(id: string, update: Partial<ChildProcess>): void {\n const oldProcess = arrayFind(this.processes, (p) => p.id === id);\n const wasRunning = oldProcess?.state === 'running';\n const isNowComplete = update.state && update.state !== 'running';\n\n this.processes = this.processes.map((p) => (p.id === id ? { ...p, ...update } : p));\n\n // Track completion order\n if (wasRunning && isNowComplete && !this.completedIds.includes(id)) {\n this.completedIds = [...this.completedIds, id];\n }\n\n // Auto-expand error footer when all complete with errors (non-interactive only)\n if (!this.isInteractive && this.isAllComplete() && this.getErrorCount() > 0) {\n this.errorFooterExpanded = true;\n }\n\n this.notify();\n }\n\n appendLines(id: string, newLines: Line[]): void {\n const process = arrayFind(this.processes, (p) => p.id === id);\n if (process) {\n this.updateProcess(id, { lines: process.lines.concat(newLines) });\n }\n }\n\n getProcess(id: string): ChildProcess | undefined {\n return arrayFind(this.processes, (p) => p.id === id);\n }\n\n // Get rendered lines from terminal buffer or fallback to lines array\n getProcessLines(id: string): Line[] {\n const process = this.getProcess(id);\n if (!process) return [];\n if (process.terminalBuffer) {\n return process.terminalBuffer.getLines().map((text) => ({\n type: LineType.stdout,\n text,\n }));\n }\n return process.lines;\n }\n\n // Get line count from terminal buffer or lines array\n getProcessLineCount(id: string): number {\n const process = this.getProcess(id);\n if (!process) return 0;\n if (process.terminalBuffer) {\n return process.terminalBuffer.lineCount;\n }\n return process.lines.length;\n }\n\n // UI state mutations\n setMode(mode: Mode): void {\n this.mode = mode;\n if (mode === 'interactive') {\n this.selectedIndex = 0;\n }\n this.notify();\n }\n\n // Interactive mode navigation\n selectNext(visibleCount?: number): void {\n if (this.processes.length > 0) {\n this.selectedIndex = (this.selectedIndex + 1) % this.processes.length;\n this.adjustListScroll(visibleCount);\n this.notify();\n }\n }\n\n selectPrev(visibleCount?: number): void {\n if (this.processes.length > 0) {\n this.selectedIndex = (this.selectedIndex - 1 + this.processes.length) % this.processes.length;\n this.adjustListScroll(visibleCount);\n this.notify();\n }\n }\n\n private adjustListScroll(visibleCount?: number): void {\n if (!visibleCount || visibleCount <= 0) return;\n\n // Ensure selected item is visible in viewport\n if (this.selectedIndex < this.listScrollOffset) {\n // Selected is above viewport - scroll up\n this.listScrollOffset = this.selectedIndex;\n } else if (this.selectedIndex >= this.listScrollOffset + visibleCount) {\n // Selected is below viewport - scroll down\n this.listScrollOffset = this.selectedIndex - visibleCount + 1;\n }\n }\n\n getSelectedProcess(): ChildProcess | undefined {\n return this.processes[this.selectedIndex];\n }\n\n // Error footer methods (for non-interactive mode)\n toggleErrorFooter(): void {\n this.errorFooterExpanded = !this.errorFooterExpanded;\n this.notify();\n }\n\n expandErrorFooter(): void {\n if (!this.errorFooterExpanded) {\n this.errorFooterExpanded = true;\n this.notify();\n }\n }\n\n getErrorLines(): Array<{ processName: string; lines: Line[] }> {\n return this.getFailedProcesses().map((p) => ({\n processName: p.group || p.title,\n lines: this.getProcessLines(p.id),\n }));\n }\n\n // Expansion methods\n toggleExpand(): void {\n const selected = this.getSelectedProcess();\n if (!selected) return;\n\n if (this.expandedId === selected.id) {\n // Collapse\n this.expandedId = null;\n this.scrollOffset = 0;\n } else {\n // Expand\n this.expandedId = selected.id;\n this.scrollOffset = 0;\n }\n this.notify();\n }\n\n collapse(): void {\n this.expandedId = null;\n this.scrollOffset = 0;\n this.notify();\n }\n\n scrollDown(maxVisible: number): void {\n if (!this.expandedId) return;\n const lineCount = this.getProcessLineCount(this.expandedId);\n if (lineCount === 0) return;\n\n const maxOffset = Math.max(0, lineCount - maxVisible);\n if (this.scrollOffset < maxOffset) {\n this.scrollOffset++;\n this.notify();\n }\n }\n\n scrollUp(): void {\n if (!this.expandedId) return;\n if (this.scrollOffset > 0) {\n this.scrollOffset--;\n this.notify();\n }\n }\n\n // Page scrolling (scroll by maxVisible lines at once)\n scrollPageDown(maxVisible: number): void {\n if (!this.expandedId) return;\n const lineCount = this.getProcessLineCount(this.expandedId);\n if (lineCount === 0) return;\n\n const maxOffset = Math.max(0, lineCount - maxVisible);\n this.scrollOffset = Math.min(this.scrollOffset + maxVisible, maxOffset);\n this.notify();\n }\n\n scrollPageUp(maxVisible: number): void {\n if (!this.expandedId) return;\n this.scrollOffset = Math.max(0, this.scrollOffset - maxVisible);\n this.notify();\n }\n\n // Jump to top/bottom\n scrollToTop(): void {\n if (!this.expandedId) return;\n this.scrollOffset = 0;\n this.notify();\n }\n\n scrollToBottom(maxVisible: number): void {\n if (!this.expandedId) return;\n const lineCount = this.getProcessLineCount(this.expandedId);\n if (lineCount === 0) return;\n\n this.scrollOffset = Math.max(0, lineCount - maxVisible);\n this.notify();\n }\n\n // Exit signaling\n signalExit(callback: () => void): void {\n this.shouldExit = true;\n this.exitCallback = callback;\n this.notify();\n }\n\n getShouldExit = (): boolean => this.shouldExit;\n getExitCallback = (): (() => void) | null => this.exitCallback;\n\n reset(): void {\n // Dispose terminal buffers before clearing\n for (const process of this.processes) {\n process.terminalBuffer?.dispose();\n }\n this.processes = [];\n this.completedIds = [];\n this.shouldExit = false;\n this.exitCallback = null;\n this.mode = 'normal';\n this.selectedIndex = 0;\n this.expandedId = null;\n this.scrollOffset = 0;\n this.listScrollOffset = 0;\n this.errorFooterExpanded = false;\n this.header = undefined;\n }\n\n // Public notify for session to trigger updates when terminal buffer changes\n notify(): void {\n this.bufferVersion++;\n this.listeners.forEach((l) => {\n l();\n });\n }\n}\n\n// Note: No global singleton - session creates its own store instance\n"],"names":["arrayFind","DEFAULT_COLUMN_WIDTH","LineType","ProcessStore","addProcess","process","processes","notify","updateProcess","id","update","oldProcess","p","wasRunning","state","isNowComplete","map","completedIds","includes","isInteractive","isAllComplete","getErrorCount","errorFooterExpanded","appendLines","newLines","lines","concat","getProcess","getProcessLines","terminalBuffer","getLines","text","type","stdout","getProcessLineCount","lineCount","length","setMode","mode","selectedIndex","selectNext","visibleCount","adjustListScroll","selectPrev","listScrollOffset","getSelectedProcess","toggleErrorFooter","expandErrorFooter","getErrorLines","getFailedProcesses","processName","group","title","toggleExpand","selected","expandedId","scrollOffset","collapse","scrollDown","maxVisible","maxOffset","Math","max","scrollUp","scrollPageDown","min","scrollPageUp","scrollToTop","scrollToBottom","signalExit","callback","shouldExit","exitCallback","reset","dispose","header","undefined","bufferVersion","listeners","forEach","l","options","Set","showStatusBar","subscribe","listener","add","delete","getSnapshot","getRunningProcesses","filter","getCompletedProcesses","getRunningCount","getMaxGroupLength","getDoneCount","getErrorLineCount","reduce","total","getMode","getSelectedIndex","getExpandedId","getScrollOffset","getListScrollOffset","getErrorFooterExpanded","getBufferVersion","getHeader","getShowStatusBar","getIsInteractive","every","getShouldExit","getExitCallback","interactive"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/node/spawn-term/src/state/processStore.ts"],"sourcesContent":["import { arrayFind } from '../compat.ts';\nimport { DEFAULT_COLUMN_WIDTH } from '../constants.ts';\nimport type { ChildProcess, Line, SessionOptions } from '../types.ts';\nimport { LineType } from '../types.ts';\nimport { createNavigator, type Navigator } from './Navigator.ts';\n\ntype Listener = () => void;\ntype Mode = 'normal' | 'interactive';\n\nexport class ProcessStore {\n // === DATA: Process collection ===\n private processes: ChildProcess[] = [];\n private completedIds: string[] = []; // Track completion order\n\n // === NAVIGATION: List cursor ===\n private listNav: Navigator;\n\n // === VIEW STATE ===\n private mode: Mode = 'normal';\n private expandedId: string | null = null;\n private errorFooterExpanded = false; // For non-interactive error footer\n\n // === SESSION CONFIG (immutable after construction) ===\n private header: string | undefined;\n private showStatusBar = false;\n private isInteractive = false;\n\n // === INFRASTRUCTURE ===\n private listeners = new Set<Listener>();\n private shouldExit = false;\n private exitCallback: (() => void) | null = null;\n private bufferVersion = 0; // Increments on every notify() to trigger re-renders\n\n constructor(options: SessionOptions = {}) {\n this.header = options.header;\n this.showStatusBar = options.showStatusBar ?? false;\n this.isInteractive = options.interactive ?? false;\n\n // Create list navigator with wrap-around behavior\n this.listNav = createNavigator({\n getLength: () => this.processes.length,\n wrap: true,\n onMove: () => this.notify(),\n });\n }\n\n // === SUBSCRIPTION API (useSyncExternalStore) ===\n\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 // === DATA: Queries ===\n\n getRunningProcesses = (): ChildProcess[] => {\n return this.processes.filter((p) => p.state === 'running');\n };\n\n getCompletedProcesses = (): ChildProcess[] => {\n // Return in completion order\n return this.completedIds.map((id) => arrayFind(this.processes, (p) => p.id === id)).filter((p): p is ChildProcess => p !== undefined);\n };\n\n getFailedProcesses = (): ChildProcess[] => {\n return this.processes.filter((p) => p.state === 'error');\n };\n\n // Counts\n getRunningCount = (): number => this.processes.filter((p) => p.state === 'running').length;\n getMaxGroupLength = (): number => {\n if (this.processes.length === 0) return DEFAULT_COLUMN_WIDTH;\n return Math.max(...this.processes.map((p) => (p.group || p.title).length));\n };\n getDoneCount = (): number => this.processes.filter((p) => p.state !== 'running').length;\n getErrorCount = (): number => this.processes.filter((p) => p.state === 'error').length;\n getErrorLineCount = (): number => {\n return this.processes.filter((p) => p.state === 'error').reduce((total, p) => total + this.getProcessLineCount(p.id), 0);\n };\n\n 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 // === DATA: Mutations ===\n\n addProcess(process: ChildProcess): void {\n // Create scroll navigator for this process\n const processWithNav: ChildProcess = {\n ...process,\n scrollNav: createNavigator({\n getLength: () => this.getProcessLineCount(processWithNav.id),\n wrap: false,\n onMove: () => this.notify(),\n }),\n };\n this.processes = [...this.processes, processWithNav];\n this.notify();\n }\n\n updateProcess(id: string, update: Partial<ChildProcess>): void {\n const oldProcess = arrayFind(this.processes, (p) => p.id === id);\n const wasRunning = oldProcess?.state === 'running';\n const isNowComplete = update.state && update.state !== 'running';\n\n this.processes = this.processes.map((p) => (p.id === id ? { ...p, ...update } : p));\n\n // Track completion order\n if (wasRunning && isNowComplete && !this.completedIds.includes(id)) {\n this.completedIds = [...this.completedIds, id];\n }\n\n // Auto-expand error footer when all complete with errors (non-interactive only)\n if (!this.isInteractive && this.isAllComplete() && this.getErrorCount() > 0) {\n this.errorFooterExpanded = true;\n }\n\n this.notify();\n }\n\n appendLines(id: string, newLines: Line[]): void {\n const process = arrayFind(this.processes, (p) => p.id === id);\n if (process) {\n this.updateProcess(id, { lines: process.lines.concat(newLines) });\n }\n }\n\n getProcess(id: string): ChildProcess | undefined {\n return arrayFind(this.processes, (p) => p.id === id);\n }\n\n // Get rendered lines from terminal buffer or fallback to lines array\n getProcessLines(id: string): Line[] {\n const process = this.getProcess(id);\n if (!process) return [];\n if (process.terminalBuffer) {\n return process.terminalBuffer.getLines().map((text) => ({\n type: LineType.stdout,\n text,\n }));\n }\n return process.lines;\n }\n\n // Get line count from terminal buffer or lines array\n getProcessLineCount(id: string): number {\n const process = this.getProcess(id);\n if (!process) return 0;\n if (process.terminalBuffer) {\n return process.terminalBuffer.lineCount;\n }\n return process.lines.length;\n }\n\n // === VIEW STATE: Getters ===\n\n getMode = (): Mode => this.mode;\n getSelectedIndex = (): number => this.listNav.position;\n getExpandedId = (): string | null => this.expandedId;\n getListScrollOffset = (): number => this.listNav.viewportOffset;\n getErrorFooterExpanded = (): boolean => this.errorFooterExpanded;\n getBufferVersion = (): number => this.bufferVersion;\n\n // Get scroll offset for expanded process (or 0 if none)\n getScrollOffset = (): number => {\n if (!this.expandedId) return 0;\n const process = this.getProcess(this.expandedId);\n return process?.scrollNav?.position ?? 0;\n };\n\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 // === VIEW STATE: Mutations ===\n\n setMode(mode: Mode): void {\n this.mode = mode;\n if (mode === 'interactive') {\n this.listNav.setPosition(0);\n }\n this.notify();\n }\n\n getSelectedProcess(): ChildProcess | undefined {\n return this.processes[this.listNav.position];\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 // === NAVIGATION: List (delegates to listNav) ===\n\n selectNext(visibleCount?: number): void {\n this.listNav.down();\n if (visibleCount) {\n this.listNav.ensureVisible(visibleCount);\n }\n }\n\n selectPrev(visibleCount?: number): void {\n this.listNav.up();\n if (visibleCount) {\n this.listNav.ensureVisible(visibleCount);\n }\n }\n\n selectPageDown(pageSize: number, visibleCount?: number): void {\n this.listNav.pageDown(pageSize, visibleCount);\n }\n\n selectPageUp(pageSize: number, visibleCount?: number): void {\n this.listNav.pageUp(pageSize, visibleCount);\n }\n\n selectFirst(visibleCount?: number): void {\n this.listNav.toStart();\n if (visibleCount) {\n this.listNav.ensureVisible(visibleCount);\n }\n }\n\n selectLast(visibleCount?: number): void {\n this.listNav.toEnd();\n if (visibleCount) {\n this.listNav.ensureVisible(visibleCount);\n }\n }\n\n clampListViewport(visibleCount: number): void {\n const changed = this.listNav.clampViewport(visibleCount);\n if (changed) {\n this.notify();\n }\n }\n\n // === NAVIGATION: Expanded content (delegates to process.scrollNav) ===\n\n private getExpandedNav(): { nav: Navigator; id: string } | undefined {\n if (!this.expandedId) return undefined;\n const nav = this.getProcess(this.expandedId)?.scrollNav;\n if (!nav) return undefined;\n return { nav, id: this.expandedId };\n }\n\n scrollDown(maxVisible: number): void {\n const expanded = this.getExpandedNav();\n if (!expanded) return;\n\n const lineCount = this.getProcessLineCount(expanded.id);\n const maxOffset = Math.max(0, lineCount - maxVisible);\n\n // Only scroll if not at bottom\n if (expanded.nav.position < maxOffset) {\n expanded.nav.down();\n }\n }\n\n scrollUp(): void {\n const expanded = this.getExpandedNav();\n if (!expanded) return;\n\n if (expanded.nav.position > 0) {\n expanded.nav.up();\n }\n }\n\n scrollPageDown(pageSize: number): void {\n const expanded = this.getExpandedNav();\n if (!expanded) return;\n\n const lineCount = this.getProcessLineCount(expanded.id);\n const maxOffset = Math.max(0, lineCount - pageSize);\n\n // Clamp to max offset\n const newPosition = Math.min(expanded.nav.position + pageSize, maxOffset);\n expanded.nav.setPosition(newPosition);\n this.notify();\n }\n\n scrollPageUp(pageSize: number): void {\n const expanded = this.getExpandedNav();\n if (!expanded) return;\n\n const newPosition = Math.max(0, expanded.nav.position - pageSize);\n expanded.nav.setPosition(newPosition);\n this.notify();\n }\n\n scrollToTop(): void {\n const expanded = this.getExpandedNav();\n if (!expanded) return;\n expanded.nav.toStart();\n }\n\n scrollToBottom(maxVisible: number): void {\n const expanded = this.getExpandedNav();\n if (!expanded) return;\n\n const lineCount = this.getProcessLineCount(expanded.id);\n const newPosition = Math.max(0, lineCount - maxVisible);\n expanded.nav.setPosition(newPosition);\n this.notify();\n }\n\n // === EXPANSION ===\n\n toggleExpand(visibleCountWhenExpanded?: number, visibleCountWhenCollapsed?: number): void {\n const selected = this.getSelectedProcess();\n if (!selected) return;\n\n if (this.expandedId === selected.id) {\n // Collapse (keep scroll position for later)\n this.expandedId = null;\n // Adjust viewport to avoid empty space at bottom\n if (visibleCountWhenCollapsed) {\n this.listNav.clampViewport(visibleCountWhenCollapsed);\n }\n } else {\n // Expand (scroll position is preserved in process.scrollNav)\n this.expandedId = selected.id;\n // Adjust list scroll to keep expanded process visible\n if (visibleCountWhenExpanded) {\n this.listNav.ensureVisible(visibleCountWhenExpanded);\n }\n }\n this.notify();\n }\n\n collapse(visibleCountWhenCollapsed?: number): void {\n // Collapse but keep scroll position in process\n this.expandedId = null;\n // Adjust viewport to avoid empty space at bottom\n if (visibleCountWhenCollapsed) {\n this.listNav.clampViewport(visibleCountWhenCollapsed);\n }\n this.notify();\n }\n\n // === EXIT ===\n\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 ===\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.listNav.reset();\n this.expandedId = null;\n this.errorFooterExpanded = false;\n this.header = undefined;\n }\n\n // === INFRASTRUCTURE ===\n\n notify(): void {\n this.bufferVersion++;\n this.listeners.forEach((l) => {\n l();\n });\n }\n}\n\n// Note: No global singleton - session creates its own store instance\n"],"names":["arrayFind","DEFAULT_COLUMN_WIDTH","LineType","createNavigator","ProcessStore","getErrorLines","getFailedProcesses","map","p","processName","group","title","lines","getProcessLines","id","addProcess","process","processWithNav","scrollNav","getLength","getProcessLineCount","wrap","onMove","notify","processes","updateProcess","update","oldProcess","wasRunning","state","isNowComplete","completedIds","includes","isInteractive","isAllComplete","getErrorCount","errorFooterExpanded","appendLines","newLines","concat","getProcess","terminalBuffer","getLines","text","type","stdout","lineCount","length","setMode","mode","listNav","setPosition","getSelectedProcess","position","toggleErrorFooter","expandErrorFooter","selectNext","visibleCount","down","ensureVisible","selectPrev","up","selectPageDown","pageSize","pageDown","selectPageUp","pageUp","selectFirst","toStart","selectLast","toEnd","clampListViewport","changed","clampViewport","getExpandedNav","expandedId","undefined","nav","scrollDown","maxVisible","expanded","maxOffset","Math","max","scrollUp","scrollPageDown","newPosition","min","scrollPageUp","scrollToTop","scrollToBottom","toggleExpand","visibleCountWhenExpanded","visibleCountWhenCollapsed","selected","collapse","signalExit","callback","shouldExit","exitCallback","reset","dispose","header","bufferVersion","listeners","forEach","l","options","showStatusBar","Set","subscribe","listener","add","delete","getSnapshot","getRunningProcesses","filter","getCompletedProcesses","getRunningCount","getMaxGroupLength","getDoneCount","getErrorLineCount","reduce","total","getMode","getSelectedIndex","getExpandedId","getListScrollOffset","viewportOffset","getErrorFooterExpanded","getBufferVersion","getScrollOffset","getHeader","getShowStatusBar","getIsInteractive","every","getShouldExit","getExitCallback","interactive"],"mappings":"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"}
|
package/dist/esm/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\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) => void;\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
|
|
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) => void;\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 /** @internal Virtual terminal for ANSI interpretation */\n terminalBuffer?: TerminalBuffer;\n expanded?: boolean;\n /** @internal Per-process scroll navigation state */\n scrollNav?: import('./state/Navigator.ts').Navigator;\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.1.
|
|
3
|
+
"version": "3.1.5",
|
|
4
4
|
"description": "Formats spawn with for terminal grouping",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"spawn",
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
],
|
|
36
36
|
"scripts": {
|
|
37
37
|
"build": "tsds build",
|
|
38
|
-
"format": "
|
|
38
|
+
"format": "tsds format",
|
|
39
39
|
"prepublishOnly": "tsds validate",
|
|
40
40
|
"test": "tsds test:node --no-timeouts",
|
|
41
41
|
"test:engines": "nvu engines tsds test:node --no-timeouts",
|
|
@@ -50,7 +50,6 @@
|
|
|
50
50
|
"react": "*"
|
|
51
51
|
},
|
|
52
52
|
"devDependencies": {
|
|
53
|
-
"@biomejs/biome": "*",
|
|
54
53
|
"@types/mocha": "*",
|
|
55
54
|
"@types/node": "*",
|
|
56
55
|
"@types/react": "*",
|
|
@@ -58,7 +57,8 @@
|
|
|
58
57
|
"is-version": "*",
|
|
59
58
|
"node-version-use": "*",
|
|
60
59
|
"pinkie-promise": "*",
|
|
61
|
-
"ts-dev-stack": "*"
|
|
60
|
+
"ts-dev-stack": "*",
|
|
61
|
+
"tsds-config": "*"
|
|
62
62
|
},
|
|
63
63
|
"engines": {
|
|
64
64
|
"node": ">=0.8"
|