spawn-term 1.1.8 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/components/App.js +96 -9
- package/dist/cjs/components/App.js.map +1 -1
- package/dist/cjs/components/CompactProcessLine.js +153 -0
- package/dist/cjs/components/CompactProcessLine.js.map +1 -0
- package/dist/cjs/components/Divider.js +24 -0
- package/dist/cjs/components/Divider.js.map +1 -0
- package/dist/cjs/components/ErrorDetailModal.js +115 -0
- package/dist/cjs/components/ErrorDetailModal.js.map +1 -0
- package/dist/cjs/components/ErrorListModal.js +135 -0
- package/dist/cjs/components/ErrorListModal.js.map +1 -0
- package/dist/cjs/components/StatusBar.js +104 -0
- package/dist/cjs/components/StatusBar.js.map +1 -0
- package/dist/cjs/createApp.js +10 -5
- package/dist/cjs/createApp.js.map +1 -1
- package/dist/cjs/src/components/CompactProcessLine.d.ts +6 -0
- package/dist/cjs/src/components/Divider.d.ts +2 -0
- package/dist/cjs/src/components/ErrorDetailModal.d.ts +8 -0
- package/dist/cjs/src/components/ErrorListModal.d.ts +8 -0
- package/dist/cjs/src/components/StatusBar.d.ts +8 -0
- package/dist/cjs/src/state/processStore.d.ts +17 -0
- package/dist/cjs/state/processStore.js +98 -0
- package/dist/cjs/state/processStore.js.map +1 -1
- package/dist/esm/components/App.js +94 -9
- package/dist/esm/components/App.js.map +1 -1
- package/dist/esm/components/CompactProcessLine.js +134 -0
- package/dist/esm/components/CompactProcessLine.js.map +1 -0
- package/dist/esm/components/Divider.js +13 -0
- package/dist/esm/components/Divider.js.map +1 -0
- package/dist/esm/components/ErrorDetailModal.js +99 -0
- package/dist/esm/components/ErrorDetailModal.js.map +1 -0
- package/dist/esm/components/ErrorListModal.js +116 -0
- package/dist/esm/components/ErrorListModal.js.map +1 -0
- package/dist/esm/components/StatusBar.js +87 -0
- package/dist/esm/components/StatusBar.js.map +1 -0
- package/dist/esm/createApp.js +10 -5
- package/dist/esm/createApp.js.map +1 -1
- package/dist/esm/src/components/CompactProcessLine.d.ts +6 -0
- package/dist/esm/src/components/Divider.d.ts +2 -0
- package/dist/esm/src/components/ErrorDetailModal.d.ts +8 -0
- package/dist/esm/src/components/ErrorListModal.d.ts +8 -0
- package/dist/esm/src/components/StatusBar.d.ts +8 -0
- package/dist/esm/src/state/processStore.d.ts +17 -0
- package/dist/esm/state/processStore.js +65 -0
- package/dist/esm/state/processStore.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
Object.defineProperty(exports, "default", {
|
|
6
|
+
enumerable: true,
|
|
7
|
+
get: function() {
|
|
8
|
+
return _default;
|
|
9
|
+
}
|
|
10
|
+
});
|
|
11
|
+
var _jsxruntime = require("react/jsx-runtime");
|
|
12
|
+
var _ink = require("ink");
|
|
13
|
+
var _react = require("react");
|
|
14
|
+
var _figurests = /*#__PURE__*/ _interop_require_default(require("../lib/figures.js"));
|
|
15
|
+
var _Spinnerts = /*#__PURE__*/ _interop_require_default(require("./Spinner.js"));
|
|
16
|
+
function _define_property(obj, key, value) {
|
|
17
|
+
if (key in obj) {
|
|
18
|
+
Object.defineProperty(obj, key, {
|
|
19
|
+
value: value,
|
|
20
|
+
enumerable: true,
|
|
21
|
+
configurable: true,
|
|
22
|
+
writable: true
|
|
23
|
+
});
|
|
24
|
+
} else {
|
|
25
|
+
obj[key] = value;
|
|
26
|
+
}
|
|
27
|
+
return obj;
|
|
28
|
+
}
|
|
29
|
+
function _interop_require_default(obj) {
|
|
30
|
+
return obj && obj.__esModule ? obj : {
|
|
31
|
+
default: obj
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
function _object_spread(target) {
|
|
35
|
+
for(var i = 1; i < arguments.length; i++){
|
|
36
|
+
var source = arguments[i] != null ? arguments[i] : {};
|
|
37
|
+
var ownKeys = Object.keys(source);
|
|
38
|
+
if (typeof Object.getOwnPropertySymbols === "function") {
|
|
39
|
+
ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function(sym) {
|
|
40
|
+
return Object.getOwnPropertyDescriptor(source, sym).enumerable;
|
|
41
|
+
}));
|
|
42
|
+
}
|
|
43
|
+
ownKeys.forEach(function(key) {
|
|
44
|
+
_define_property(target, key, source[key]);
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
return target;
|
|
48
|
+
}
|
|
49
|
+
// From: https://github.com/sindresorhus/cli-spinners/blob/00de8fbeee16fa49502fa4f687449f70f2c8ca2c/spinners.json#L2
|
|
50
|
+
var SPINNER = {
|
|
51
|
+
interval: 80,
|
|
52
|
+
frames: [
|
|
53
|
+
'⠋',
|
|
54
|
+
'⠙',
|
|
55
|
+
'⠹',
|
|
56
|
+
'⠸',
|
|
57
|
+
'⠼',
|
|
58
|
+
'⠴',
|
|
59
|
+
'⠦',
|
|
60
|
+
'⠧',
|
|
61
|
+
'⠇',
|
|
62
|
+
'⠏'
|
|
63
|
+
]
|
|
64
|
+
};
|
|
65
|
+
var _default = /*#__PURE__*/ (0, _react.memo)(function StatusBar(param) {
|
|
66
|
+
var running = param.running, done = param.done, errors = param.errors, errorLines = param.errorLines;
|
|
67
|
+
return /*#__PURE__*/ (0, _jsxruntime.jsxs)(_ink.Box, {
|
|
68
|
+
justifyContent: "space-between",
|
|
69
|
+
children: [
|
|
70
|
+
/*#__PURE__*/ (0, _jsxruntime.jsx)(_ink.Box, {
|
|
71
|
+
children: /*#__PURE__*/ (0, _jsxruntime.jsxs)(_ink.Text, {
|
|
72
|
+
children: [
|
|
73
|
+
running > 0 ? /*#__PURE__*/ (0, _jsxruntime.jsx)(_Spinnerts.default, _object_spread({}, SPINNER)) : /*#__PURE__*/ (0, _jsxruntime.jsx)(_ink.Text, {
|
|
74
|
+
color: "green",
|
|
75
|
+
children: _figurests.default.tick
|
|
76
|
+
}),
|
|
77
|
+
" Running: ".concat(running, " "),
|
|
78
|
+
/*#__PURE__*/ (0, _jsxruntime.jsx)(_ink.Text, {
|
|
79
|
+
color: "green",
|
|
80
|
+
children: _figurests.default.tick
|
|
81
|
+
}),
|
|
82
|
+
" Done: ".concat(done, " "),
|
|
83
|
+
/*#__PURE__*/ (0, _jsxruntime.jsx)(_ink.Text, {
|
|
84
|
+
color: "red",
|
|
85
|
+
children: _figurests.default.cross
|
|
86
|
+
}),
|
|
87
|
+
" Errors: ".concat(errors),
|
|
88
|
+
errorLines > 0 && /*#__PURE__*/ (0, _jsxruntime.jsx)(_ink.Text, {
|
|
89
|
+
dimColor: true,
|
|
90
|
+
children: " (".concat(errorLines, " lines)")
|
|
91
|
+
})
|
|
92
|
+
]
|
|
93
|
+
})
|
|
94
|
+
}),
|
|
95
|
+
errors > 0 && /*#__PURE__*/ (0, _jsxruntime.jsx)(_ink.Box, {
|
|
96
|
+
children: /*#__PURE__*/ (0, _jsxruntime.jsx)(_ink.Text, {
|
|
97
|
+
dimColor: true,
|
|
98
|
+
children: "[e]rrors"
|
|
99
|
+
})
|
|
100
|
+
})
|
|
101
|
+
]
|
|
102
|
+
});
|
|
103
|
+
});
|
|
104
|
+
/* CJS INTEROP */ if (exports.__esModule && exports.default) { try { Object.defineProperty(exports.default, '__esModule', { value: true }); for (var key in exports) { exports.default[key] = exports[key]; } } catch (_) {}; module.exports = exports.default; }
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/node/spawn-term/src/components/StatusBar.tsx"],"sourcesContent":["import { Box, Text } from 'ink';\nimport { memo } from 'react';\nimport figures from '../lib/figures.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 running: number;\n done: number;\n errors: number;\n errorLines: number;\n};\n\nexport default memo(function StatusBar({ running, done, errors, errorLines }: Props) {\n return (\n <Box justifyContent=\"space-between\">\n <Box>\n <Text>\n {running > 0 ? <Spinner {...SPINNER} /> : <Text color=\"green\">{figures.tick}</Text>}\n {` Running: ${running} `}\n <Text color=\"green\">{figures.tick}</Text>\n {` Done: ${done} `}\n <Text color=\"red\">{figures.cross}</Text>\n {` Errors: ${errors}`}\n {errorLines > 0 && <Text dimColor>{` (${errorLines} lines)`}</Text>}\n </Text>\n </Box>\n {errors > 0 && (\n <Box>\n <Text dimColor>[e]rrors</Text>\n </Box>\n )}\n </Box>\n );\n});\n"],"names":["SPINNER","interval","frames","memo","StatusBar","running","done","errors","errorLines","Box","justifyContent","Text","Spinner","color","figures","tick","cross","dimColor"],"mappings":";;;;+BAkBA;;;eAAA;;;;mBAlB0B;qBACL;gEACD;gEACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEpB,oHAAoH;AACpH,IAAMA,UAAU;IACdC,UAAU;IACVC,QAAQ;QAAC;QAAK;QAAK;QAAK;QAAK;QAAK;QAAK;QAAK;QAAK;QAAK;KAAI;AAC5D;IASA,yBAAeC,IAAAA,WAAI,EAAC,SAASC,UAAU,KAA4C;QAA1CC,UAAF,MAAEA,SAASC,OAAX,MAAWA,MAAMC,SAAjB,MAAiBA,QAAQC,aAAzB,MAAyBA;IAC9D,qBACE,sBAACC,QAAG;QAACC,gBAAe;;0BAClB,qBAACD,QAAG;0BACF,cAAA,sBAACE,SAAI;;wBACFN,UAAU,kBAAI,qBAACO,kBAAO,qBAAKZ,0BAAc,qBAACW,SAAI;4BAACE,OAAM;sCAASC,kBAAO,CAACC,IAAI;;wBACzE,aAAoB,OAARV,SAAQ;sCACtB,qBAACM,SAAI;4BAACE,OAAM;sCAASC,kBAAO,CAACC,IAAI;;wBAC/B,UAAc,OAALT,MAAK;sCAChB,qBAACK,SAAI;4BAACE,OAAM;sCAAOC,kBAAO,CAACE,KAAK;;wBAC9B,YAAkB,OAAPT;wBACZC,aAAa,mBAAK,qBAACG,SAAI;4BAACM,QAAQ;sCAAE,AAAC,KAAe,OAAXT,YAAW;;;;;YAGtDD,SAAS,mBACR,qBAACE,QAAG;0BACF,cAAA,qBAACE,SAAI;oBAACM,QAAQ;8BAAC;;;;;AAKzB"}
|
package/dist/cjs/createApp.js
CHANGED
|
@@ -33,11 +33,16 @@ function createApp() {
|
|
|
33
33
|
return;
|
|
34
34
|
}
|
|
35
35
|
if (!inkApp) throw new Error('Expecting inkApp');
|
|
36
|
-
//
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
36
|
+
// Defer signalExit to allow React's reconciliation to complete fully
|
|
37
|
+
// Using setImmediate ensures we run after I/O callbacks and microtasks,
|
|
38
|
+
// preventing the Static component from outputting the last item twice
|
|
39
|
+
// (the second notify() from signalExit can race with Static's useLayoutEffect)
|
|
40
|
+
setImmediate(function() {
|
|
41
|
+
_processStorets.processStore.signalExit(function() {
|
|
42
|
+
_processStorets.processStore.reset();
|
|
43
|
+
process.stdout.write('\x1b[?25h'); // show cursor
|
|
44
|
+
callback();
|
|
45
|
+
});
|
|
41
46
|
});
|
|
42
47
|
// Wait for Ink to finish, then call the callback
|
|
43
48
|
inkApp.waitUntilExit().then(function() {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/node/spawn-term/src/createApp.tsx"],"sourcesContent":["import { render } from 'ink';\nimport App from './components/App.ts';\nimport { type ProcessStore, processStore } from './state/processStore.ts';\n\nexport type ReleaseCallback = () => void;\n\nexport default function createApp() {\n let refCount = 0;\n let inkApp: ReturnType<typeof render> | null = null;\n\n return {\n retain(): ProcessStore {\n if (++refCount > 1) return processStore;\n\n // Render once - React handles all subsequent updates via useSyncExternalStore\n inkApp = render(<App />);\n return processStore;\n },\n\n release(callback: ReleaseCallback): void {\n if (--refCount > 0) {\n callback();\n return;\n }\n if (!inkApp) throw new Error('Expecting inkApp');\n\n //
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/node/spawn-term/src/createApp.tsx"],"sourcesContent":["import { render } from 'ink';\nimport App from './components/App.ts';\nimport { type ProcessStore, processStore } from './state/processStore.ts';\n\nexport type ReleaseCallback = () => void;\n\nexport default function createApp() {\n let refCount = 0;\n let inkApp: ReturnType<typeof render> | null = null;\n\n return {\n retain(): ProcessStore {\n if (++refCount > 1) return processStore;\n\n // Render once - React handles all subsequent updates via useSyncExternalStore\n inkApp = render(<App />);\n return processStore;\n },\n\n release(callback: ReleaseCallback): void {\n if (--refCount > 0) {\n callback();\n return;\n }\n if (!inkApp) throw new Error('Expecting inkApp');\n\n // Defer signalExit to allow React's reconciliation to complete fully\n // Using setImmediate ensures we run after I/O callbacks and microtasks,\n // preventing the Static component from outputting the last item twice\n // (the second notify() from signalExit can race with Static's useLayoutEffect)\n setImmediate(() => {\n processStore.signalExit(() => {\n processStore.reset();\n process.stdout.write('\\x1b[?25h'); // show cursor\n callback();\n });\n });\n\n // Wait for Ink to finish, then call the callback\n inkApp\n .waitUntilExit()\n .then(() => {\n const cb = processStore.getExitCallback();\n cb?.();\n })\n .catch(() => {\n const cb = processStore.getExitCallback();\n cb?.();\n });\n\n inkApp = null;\n },\n };\n}\n"],"names":["createApp","refCount","inkApp","retain","processStore","render","App","release","callback","Error","setImmediate","signalExit","reset","process","stdout","write","waitUntilExit","then","cb","getExitCallback","catch"],"mappings":";;;;+BAMA;;;eAAwBA;;;;mBAND;4DACP;8BACgC;;;;;;AAIjC,SAASA;IACtB,IAAIC,WAAW;IACf,IAAIC,SAA2C;IAE/C,OAAO;QACLC,QAAAA,SAAAA;YACE,IAAI,EAAEF,WAAW,GAAG,OAAOG,4BAAY;YAEvC,8EAA8E;YAC9EF,SAASG,IAAAA,WAAM,gBAAC,qBAACC,cAAG;YACpB,OAAOF,4BAAY;QACrB;QAEAG,SAAAA,SAAAA,QAAQC,QAAyB;YAC/B,IAAI,EAAEP,WAAW,GAAG;gBAClBO;gBACA;YACF;YACA,IAAI,CAACN,QAAQ,MAAM,IAAIO,MAAM;YAE7B,qEAAqE;YACrE,wEAAwE;YACxE,sEAAsE;YACtE,+EAA+E;YAC/EC,aAAa;gBACXN,4BAAY,CAACO,UAAU,CAAC;oBACtBP,4BAAY,CAACQ,KAAK;oBAClBC,QAAQC,MAAM,CAACC,KAAK,CAAC,cAAc,cAAc;oBACjDP;gBACF;YACF;YAEA,iDAAiD;YACjDN,OACGc,aAAa,GACbC,IAAI,CAAC;gBACJ,IAAMC,KAAKd,4BAAY,CAACe,eAAe;gBACvCD,eAAAA,yBAAAA;YACF,GACCE,KAAK,CAAC;gBACL,IAAMF,KAAKd,4BAAY,CAACe,eAAe;gBACvCD,eAAAA,yBAAAA;YACF;YAEFhB,SAAS;QACX;IACF;AACF"}
|
|
@@ -1,16 +1,33 @@
|
|
|
1
1
|
import type { ChildProcess, Line } from '../types.js';
|
|
2
2
|
type Listener = () => void;
|
|
3
|
+
type Mode = 'normal' | 'errorList' | 'errorDetail';
|
|
3
4
|
declare class ProcessStore {
|
|
4
5
|
private processes;
|
|
6
|
+
private completedIds;
|
|
5
7
|
private listeners;
|
|
6
8
|
private shouldExit;
|
|
7
9
|
private exitCallback;
|
|
10
|
+
private mode;
|
|
11
|
+
private selectedErrorIndex;
|
|
8
12
|
subscribe: (listener: Listener) => (() => void);
|
|
9
13
|
getSnapshot: () => ChildProcess[];
|
|
14
|
+
getRunningProcesses: () => ChildProcess[];
|
|
15
|
+
getCompletedProcesses: () => ChildProcess[];
|
|
16
|
+
getFailedProcesses: () => ChildProcess[];
|
|
17
|
+
getRunningCount: () => number;
|
|
18
|
+
getDoneCount: () => number;
|
|
19
|
+
getErrorCount: () => number;
|
|
20
|
+
getErrorLineCount: () => number;
|
|
21
|
+
getMode: () => Mode;
|
|
22
|
+
getSelectedErrorIndex: () => number;
|
|
10
23
|
addProcess(process: ChildProcess): void;
|
|
11
24
|
updateProcess(id: string, update: Partial<ChildProcess>): void;
|
|
12
25
|
appendLines(id: string, newLines: Line[]): void;
|
|
13
26
|
getProcess(id: string): ChildProcess | undefined;
|
|
27
|
+
setMode(mode: Mode): void;
|
|
28
|
+
selectNextError(): void;
|
|
29
|
+
selectPrevError(): void;
|
|
30
|
+
getSelectedError(): ChildProcess | undefined;
|
|
14
31
|
signalExit(callback: () => void): void;
|
|
15
32
|
getShouldExit: () => boolean;
|
|
16
33
|
getExitCallback: () => (() => void) | null;
|
|
@@ -8,6 +8,7 @@ Object.defineProperty(exports, "processStore", {
|
|
|
8
8
|
return processStore;
|
|
9
9
|
}
|
|
10
10
|
});
|
|
11
|
+
var _typests = require("../types.js");
|
|
11
12
|
function _array_like_to_array(arr, len) {
|
|
12
13
|
if (len == null || len > arr.length) len = arr.length;
|
|
13
14
|
for(var i = 0, arr2 = new Array(len); i < len; i++)arr2[i] = arr[i];
|
|
@@ -72,9 +73,13 @@ var ProcessStore = /*#__PURE__*/ function() {
|
|
|
72
73
|
var _this = this;
|
|
73
74
|
_class_call_check(this, ProcessStore);
|
|
74
75
|
this.processes = [];
|
|
76
|
+
this.completedIds = []; // Track completion order
|
|
75
77
|
this.listeners = new Set();
|
|
76
78
|
this.shouldExit = false;
|
|
77
79
|
this.exitCallback = null;
|
|
80
|
+
// UI state
|
|
81
|
+
this.mode = 'normal';
|
|
82
|
+
this.selectedErrorIndex = 0;
|
|
78
83
|
// useSyncExternalStore API
|
|
79
84
|
this.subscribe = function(listener) {
|
|
80
85
|
_this.listeners.add(listener);
|
|
@@ -85,6 +90,59 @@ var ProcessStore = /*#__PURE__*/ function() {
|
|
|
85
90
|
this.getSnapshot = function() {
|
|
86
91
|
return _this.processes;
|
|
87
92
|
};
|
|
93
|
+
// Filtered getters
|
|
94
|
+
this.getRunningProcesses = function() {
|
|
95
|
+
return _this.processes.filter(function(p) {
|
|
96
|
+
return p.state === 'running';
|
|
97
|
+
});
|
|
98
|
+
};
|
|
99
|
+
this.getCompletedProcesses = function() {
|
|
100
|
+
// Return in completion order
|
|
101
|
+
return _this.completedIds.map(function(id) {
|
|
102
|
+
return _this.processes.find(function(p) {
|
|
103
|
+
return p.id === id;
|
|
104
|
+
});
|
|
105
|
+
}).filter(function(p) {
|
|
106
|
+
return p !== undefined;
|
|
107
|
+
});
|
|
108
|
+
};
|
|
109
|
+
this.getFailedProcesses = function() {
|
|
110
|
+
return _this.processes.filter(function(p) {
|
|
111
|
+
return p.state === 'error';
|
|
112
|
+
});
|
|
113
|
+
};
|
|
114
|
+
// Counts
|
|
115
|
+
this.getRunningCount = function() {
|
|
116
|
+
return _this.processes.filter(function(p) {
|
|
117
|
+
return p.state === 'running';
|
|
118
|
+
}).length;
|
|
119
|
+
};
|
|
120
|
+
this.getDoneCount = function() {
|
|
121
|
+
return _this.processes.filter(function(p) {
|
|
122
|
+
return p.state !== 'running';
|
|
123
|
+
}).length;
|
|
124
|
+
};
|
|
125
|
+
this.getErrorCount = function() {
|
|
126
|
+
return _this.processes.filter(function(p) {
|
|
127
|
+
return p.state === 'error';
|
|
128
|
+
}).length;
|
|
129
|
+
};
|
|
130
|
+
this.getErrorLineCount = function() {
|
|
131
|
+
return _this.processes.filter(function(p) {
|
|
132
|
+
return p.state === 'error';
|
|
133
|
+
}).reduce(function(total, p) {
|
|
134
|
+
return total + p.lines.filter(function(l) {
|
|
135
|
+
return l.type === _typests.LineType.stderr;
|
|
136
|
+
}).length;
|
|
137
|
+
}, 0);
|
|
138
|
+
};
|
|
139
|
+
// UI state getters
|
|
140
|
+
this.getMode = function() {
|
|
141
|
+
return _this.mode;
|
|
142
|
+
};
|
|
143
|
+
this.getSelectedErrorIndex = function() {
|
|
144
|
+
return _this.selectedErrorIndex;
|
|
145
|
+
};
|
|
88
146
|
this.getShouldExit = function() {
|
|
89
147
|
return _this.shouldExit;
|
|
90
148
|
};
|
|
@@ -101,9 +159,20 @@ var ProcessStore = /*#__PURE__*/ function() {
|
|
|
101
159
|
this.notify();
|
|
102
160
|
};
|
|
103
161
|
_proto.updateProcess = function updateProcess(id, update) {
|
|
162
|
+
var oldProcess = this.processes.find(function(p) {
|
|
163
|
+
return p.id === id;
|
|
164
|
+
});
|
|
165
|
+
var wasRunning = (oldProcess === null || oldProcess === void 0 ? void 0 : oldProcess.state) === 'running';
|
|
166
|
+
var isNowComplete = update.state && update.state !== 'running';
|
|
104
167
|
this.processes = this.processes.map(function(p) {
|
|
105
168
|
return p.id === id ? _object_spread({}, p, update) : p;
|
|
106
169
|
});
|
|
170
|
+
// Track completion order
|
|
171
|
+
if (wasRunning && isNowComplete && !this.completedIds.includes(id)) {
|
|
172
|
+
this.completedIds = _to_consumable_array(this.completedIds).concat([
|
|
173
|
+
id
|
|
174
|
+
]);
|
|
175
|
+
}
|
|
107
176
|
this.notify();
|
|
108
177
|
};
|
|
109
178
|
_proto.appendLines = function appendLines(id, newLines) {
|
|
@@ -121,6 +190,32 @@ var ProcessStore = /*#__PURE__*/ function() {
|
|
|
121
190
|
return p.id === id;
|
|
122
191
|
});
|
|
123
192
|
};
|
|
193
|
+
// UI state mutations
|
|
194
|
+
_proto.setMode = function setMode(mode) {
|
|
195
|
+
this.mode = mode;
|
|
196
|
+
if (mode === 'errorList') {
|
|
197
|
+
this.selectedErrorIndex = 0;
|
|
198
|
+
}
|
|
199
|
+
this.notify();
|
|
200
|
+
};
|
|
201
|
+
_proto.selectNextError = function selectNextError() {
|
|
202
|
+
var failed = this.getFailedProcesses();
|
|
203
|
+
if (failed.length > 0) {
|
|
204
|
+
this.selectedErrorIndex = (this.selectedErrorIndex + 1) % failed.length;
|
|
205
|
+
this.notify();
|
|
206
|
+
}
|
|
207
|
+
};
|
|
208
|
+
_proto.selectPrevError = function selectPrevError() {
|
|
209
|
+
var failed = this.getFailedProcesses();
|
|
210
|
+
if (failed.length > 0) {
|
|
211
|
+
this.selectedErrorIndex = (this.selectedErrorIndex - 1 + failed.length) % failed.length;
|
|
212
|
+
this.notify();
|
|
213
|
+
}
|
|
214
|
+
};
|
|
215
|
+
_proto.getSelectedError = function getSelectedError() {
|
|
216
|
+
var failed = this.getFailedProcesses();
|
|
217
|
+
return failed[this.selectedErrorIndex];
|
|
218
|
+
};
|
|
124
219
|
// Exit signaling
|
|
125
220
|
_proto.signalExit = function signalExit(callback) {
|
|
126
221
|
this.shouldExit = true;
|
|
@@ -129,8 +224,11 @@ var ProcessStore = /*#__PURE__*/ function() {
|
|
|
129
224
|
};
|
|
130
225
|
_proto.reset = function reset() {
|
|
131
226
|
this.processes = [];
|
|
227
|
+
this.completedIds = [];
|
|
132
228
|
this.shouldExit = false;
|
|
133
229
|
this.exitCallback = null;
|
|
230
|
+
this.mode = 'normal';
|
|
231
|
+
this.selectedErrorIndex = 0;
|
|
134
232
|
};
|
|
135
233
|
_proto.notify = function notify() {
|
|
136
234
|
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';\n\ntype Listener = () => void;\n\nclass ProcessStore {\n private processes: ChildProcess[] = [];\n private listeners = new Set<Listener>();\n private shouldExit = false;\n private exitCallback: (() => void) | null = null;\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 // 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 this.processes = this.processes.map((p) => (p.id === id ? { ...p, ...update } : p));\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 // 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.shouldExit = false;\n this.exitCallback = null;\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","listeners","Set","shouldExit","exitCallback","subscribe","listener","add","delete","getSnapshot","getShouldExit","getExitCallback","addProcess","process","notify","updateProcess","
|
|
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":";;;;+BA2IaA;;;eAAAA;;;uBA1IY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAKzB,IAAA,AAAMC,6BAAN;;aAAMA;;gCAAAA;aACIC,YAA4B,EAAE;aAC9BC,eAAyB,EAAE,EAAE,yBAAyB;aACtDC,YAAY,IAAIC;aAChBC,aAAa;aACbC,eAAoC;QAE5C,WAAW;aACHC,OAAa;aACbC,qBAAqB;QAE7B,2BAA2B;aAC3BC,YAAY,SAACC;YACX,MAAKP,SAAS,CAACQ,GAAG,CAACD;YACnB,OAAO;uBAAM,MAAKP,SAAS,CAACS,MAAM,CAACF;;QACrC;aAEAG,cAAc;mBAAsB,MAAKZ,SAAS;;QAElD,mBAAmB;aACnBa,sBAAsB;YACpB,OAAO,MAAKb,SAAS,CAACc,MAAM,CAAC,SAACC;uBAAMA,EAAEC,KAAK,KAAK;;QAClD;aAEAC,wBAAwB;YACtB,6BAA6B;YAC7B,OAAO,MAAKhB,YAAY,CAACiB,GAAG,CAAC,SAACC;uBAAO,MAAKnB,SAAS,CAACoB,IAAI,CAAC,SAACL;2BAAMA,EAAEI,EAAE,KAAKA;;eAAKL,MAAM,CAAC,SAACC;uBAAyBA,MAAMM;;QACvH;aAEAC,qBAAqB;YACnB,OAAO,MAAKtB,SAAS,CAACc,MAAM,CAAC,SAACC;uBAAMA,EAAEC,KAAK,KAAK;;QAClD;QAEA,SAAS;aACTO,kBAAkB;mBAAc,MAAKvB,SAAS,CAACc,MAAM,CAAC,SAACC;uBAAMA,EAAEC,KAAK,KAAK;eAAWQ,MAAM;;aAC1FC,eAAe;mBAAc,MAAKzB,SAAS,CAACc,MAAM,CAAC,SAACC;uBAAMA,EAAEC,KAAK,KAAK;eAAWQ,MAAM;;aACvFE,gBAAgB;mBAAc,MAAK1B,SAAS,CAACc,MAAM,CAAC,SAACC;uBAAMA,EAAEC,KAAK,KAAK;eAASQ,MAAM;;aACtFG,oBAAoB;YAClB,OAAO,MAAK3B,SAAS,CAACc,MAAM,CAAC,SAACC;uBAAMA,EAAEC,KAAK,KAAK;eAASY,MAAM,CAAC,SAACC,OAAOd;uBAAMc,QAAQd,EAAEe,KAAK,CAAChB,MAAM,CAAC,SAACiB;2BAAMA,EAAEC,IAAI,KAAKC,iBAAQ,CAACC,MAAM;mBAAEV,MAAM;eAAE;QAClJ;QAEA,mBAAmB;aACnBW,UAAU;mBAAY,MAAK7B,IAAI;;aAC/B8B,wBAAwB;mBAAc,MAAK7B,kBAAkB;;aAuE7D8B,gBAAgB;mBAAe,MAAKjC,UAAU;;aAC9CkC,kBAAkB;mBAA2B,MAAKjC,YAAY;;;iBAnH1DN;IA6CJ,sDAAsD;IACtDwC,OAAAA,UAGC,GAHDA,SAAAA,WAAWC,OAAqB;QAC9B,IAAI,CAACxC,SAAS,GAAG,AAAC,qBAAG,IAAI,CAACA,SAAS,SAAlB;YAAoBwC;SAAQ;QAC7C,IAAI,CAACC,MAAM;IACb;IAEAC,OAAAA,aAaC,GAbDA,SAAAA,cAAcvB,EAAU,EAAEwB,MAA6B;QACrD,IAAMC,aAAa,IAAI,CAAC5C,SAAS,CAACoB,IAAI,CAAC,SAACL;mBAAMA,EAAEI,EAAE,KAAKA;;QACvD,IAAM0B,aAAaD,CAAAA,uBAAAA,iCAAAA,WAAY5B,KAAK,MAAK;QACzC,IAAM8B,gBAAgBH,OAAO3B,KAAK,IAAI2B,OAAO3B,KAAK,KAAK;QAEvD,IAAI,CAAChB,SAAS,GAAG,IAAI,CAACA,SAAS,CAACkB,GAAG,CAAC,SAACH;mBAAOA,EAAEI,EAAE,KAAKA,KAAK,mBAAKJ,GAAM4B,UAAW5B;;QAEhF,yBAAyB;QACzB,IAAI8B,cAAcC,iBAAiB,CAAC,IAAI,CAAC7C,YAAY,CAAC8C,QAAQ,CAAC5B,KAAK;YAClE,IAAI,CAAClB,YAAY,GAAG,AAAC,qBAAG,IAAI,CAACA,YAAY,SAArB;gBAAuBkB;aAAG;QAChD;QAEA,IAAI,CAACsB,MAAM;IACb;IAEAO,OAAAA,WAKC,GALDA,SAAAA,YAAY7B,EAAU,EAAE8B,QAAgB;QACtC,IAAMT,UAAU,IAAI,CAACxC,SAAS,CAACoB,IAAI,CAAC,SAACL;mBAAMA,EAAEI,EAAE,KAAKA;;QACpD,IAAIqB,SAAS;YACX,IAAI,CAACE,aAAa,CAACvB,IAAI;gBAAEW,OAAOU,QAAQV,KAAK,CAACoB,MAAM,CAACD;YAAU;QACjE;IACF;IAEAE,OAAAA,UAEC,GAFDA,SAAAA,WAAWhC,EAAU;QACnB,OAAO,IAAI,CAACnB,SAAS,CAACoB,IAAI,CAAC,SAACL;mBAAMA,EAAEI,EAAE,KAAKA;;IAC7C;IAEA,qBAAqB;IACrBiC,OAAAA,OAMC,GANDA,SAAAA,QAAQ9C,IAAU;QAChB,IAAI,CAACA,IAAI,GAAGA;QACZ,IAAIA,SAAS,aAAa;YACxB,IAAI,CAACC,kBAAkB,GAAG;QAC5B;QACA,IAAI,CAACkC,MAAM;IACb;IAEAY,OAAAA,eAMC,GANDA,SAAAA;QACE,IAAMC,SAAS,IAAI,CAAChC,kBAAkB;QACtC,IAAIgC,OAAO9B,MAAM,GAAG,GAAG;YACrB,IAAI,CAACjB,kBAAkB,GAAG,AAAC,CAAA,IAAI,CAACA,kBAAkB,GAAG,CAAA,IAAK+C,OAAO9B,MAAM;YACvE,IAAI,CAACiB,MAAM;QACb;IACF;IAEAc,OAAAA,eAMC,GANDA,SAAAA;QACE,IAAMD,SAAS,IAAI,CAAChC,kBAAkB;QACtC,IAAIgC,OAAO9B,MAAM,GAAG,GAAG;YACrB,IAAI,CAACjB,kBAAkB,GAAG,AAAC,CAAA,IAAI,CAACA,kBAAkB,GAAG,IAAI+C,OAAO9B,MAAM,AAAD,IAAK8B,OAAO9B,MAAM;YACvF,IAAI,CAACiB,MAAM;QACb;IACF;IAEAe,OAAAA,gBAGC,GAHDA,SAAAA;QACE,IAAMF,SAAS,IAAI,CAAChC,kBAAkB;QACtC,OAAOgC,MAAM,CAAC,IAAI,CAAC/C,kBAAkB,CAAC;IACxC;IAEA,iBAAiB;IACjBkD,OAAAA,UAIC,GAJDA,SAAAA,WAAWC,QAAoB;QAC7B,IAAI,CAACtD,UAAU,GAAG;QAClB,IAAI,CAACC,YAAY,GAAGqD;QACpB,IAAI,CAACjB,MAAM;IACb;IAKAkB,OAAAA,KAOC,GAPDA,SAAAA;QACE,IAAI,CAAC3D,SAAS,GAAG,EAAE;QACnB,IAAI,CAACC,YAAY,GAAG,EAAE;QACtB,IAAI,CAACG,UAAU,GAAG;QAClB,IAAI,CAACC,YAAY,GAAG;QACpB,IAAI,CAACC,IAAI,GAAG;QACZ,IAAI,CAACC,kBAAkB,GAAG;IAC5B;IAEA,OAAQkC,MAIP,GAJD,SAAQA;QACN,IAAI,CAACvC,SAAS,CAAC0D,OAAO,CAAC,SAAC7B;YACtBA;QACF;IACF;WAlIIhC;;AAqIC,IAAMD,eAAe,IAAIC"}
|
|
@@ -1,14 +1,29 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { Box, useApp } from 'ink';
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { Box, Static, useApp, useInput, useStdin } from 'ink';
|
|
3
3
|
import { useEffect, useSyncExternalStore } from 'react';
|
|
4
4
|
import { processStore } from '../state/processStore.js';
|
|
5
|
-
import
|
|
5
|
+
import CompactProcessLine from './CompactProcessLine.js';
|
|
6
|
+
import Divider from './Divider.js';
|
|
7
|
+
import ErrorDetailModal from './ErrorDetailModal.js';
|
|
8
|
+
import ErrorListModal from './ErrorListModal.js';
|
|
9
|
+
import StatusBar from './StatusBar.js';
|
|
6
10
|
export default function App() {
|
|
7
11
|
const { exit } = useApp();
|
|
8
|
-
|
|
12
|
+
const { isRawModeSupported } = useStdin();
|
|
13
|
+
// Subscribe to store state
|
|
9
14
|
const processes = useSyncExternalStore(processStore.subscribe, processStore.getSnapshot);
|
|
10
|
-
// Handle exit signal
|
|
11
15
|
const shouldExit = useSyncExternalStore(processStore.subscribe, processStore.getShouldExit);
|
|
16
|
+
const mode = useSyncExternalStore(processStore.subscribe, processStore.getMode);
|
|
17
|
+
const selectedErrorIndex = useSyncExternalStore(processStore.subscribe, processStore.getSelectedErrorIndex);
|
|
18
|
+
// Derived state
|
|
19
|
+
const completedProcesses = processStore.getCompletedProcesses();
|
|
20
|
+
const runningProcesses = processStore.getRunningProcesses();
|
|
21
|
+
const failedProcesses = processStore.getFailedProcesses();
|
|
22
|
+
const runningCount = processStore.getRunningCount();
|
|
23
|
+
const doneCount = processStore.getDoneCount();
|
|
24
|
+
const errorCount = processStore.getErrorCount();
|
|
25
|
+
const errorLineCount = processStore.getErrorLineCount();
|
|
26
|
+
// Handle exit signal
|
|
12
27
|
useEffect(()=>{
|
|
13
28
|
if (shouldExit) {
|
|
14
29
|
exit();
|
|
@@ -17,10 +32,80 @@ export default function App() {
|
|
|
17
32
|
shouldExit,
|
|
18
33
|
exit
|
|
19
34
|
]);
|
|
20
|
-
|
|
35
|
+
// Keyboard handling (only active when raw mode is supported)
|
|
36
|
+
useInput((input, key)=>{
|
|
37
|
+
if (mode === 'normal') {
|
|
38
|
+
if (input === 'e' && errorCount > 0) {
|
|
39
|
+
processStore.setMode('errorList');
|
|
40
|
+
}
|
|
41
|
+
} else if (mode === 'errorList') {
|
|
42
|
+
if (key.escape) {
|
|
43
|
+
processStore.setMode('normal');
|
|
44
|
+
} else if (key.downArrow) {
|
|
45
|
+
processStore.selectNextError();
|
|
46
|
+
} else if (key.upArrow) {
|
|
47
|
+
processStore.selectPrevError();
|
|
48
|
+
} else if (key.return) {
|
|
49
|
+
processStore.setMode('errorDetail');
|
|
50
|
+
}
|
|
51
|
+
} else if (mode === 'errorDetail') {
|
|
52
|
+
if (key.escape) {
|
|
53
|
+
processStore.setMode('errorList');
|
|
54
|
+
} else if (key.downArrow) {
|
|
55
|
+
processStore.selectNextError();
|
|
56
|
+
} else if (key.upArrow) {
|
|
57
|
+
processStore.selectPrevError();
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}, {
|
|
61
|
+
isActive: isRawModeSupported === true
|
|
62
|
+
});
|
|
63
|
+
// Error list modal
|
|
64
|
+
if (mode === 'errorList') {
|
|
65
|
+
return /*#__PURE__*/ _jsx(ErrorListModal, {
|
|
66
|
+
errors: failedProcesses,
|
|
67
|
+
selectedIndex: selectedErrorIndex,
|
|
68
|
+
totalErrorLines: errorLineCount
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
// Error detail modal
|
|
72
|
+
if (mode === 'errorDetail') {
|
|
73
|
+
const selectedError = processStore.getSelectedError();
|
|
74
|
+
if (selectedError) {
|
|
75
|
+
return /*#__PURE__*/ _jsx(ErrorDetailModal, {
|
|
76
|
+
error: selectedError,
|
|
77
|
+
currentIndex: selectedErrorIndex,
|
|
78
|
+
totalErrors: failedProcesses.length
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
// Fallback if no error selected
|
|
82
|
+
processStore.setMode('errorList');
|
|
83
|
+
}
|
|
84
|
+
// Normal view
|
|
85
|
+
return /*#__PURE__*/ _jsxs(Box, {
|
|
21
86
|
flexDirection: "column",
|
|
22
|
-
children:
|
|
23
|
-
|
|
24
|
-
|
|
87
|
+
children: [
|
|
88
|
+
/*#__PURE__*/ _jsx(Static, {
|
|
89
|
+
items: completedProcesses,
|
|
90
|
+
children: (item)=>/*#__PURE__*/ _jsx(CompactProcessLine, {
|
|
91
|
+
item: item
|
|
92
|
+
}, item.id)
|
|
93
|
+
}),
|
|
94
|
+
completedProcesses.length > 0 && runningProcesses.length > 0 && /*#__PURE__*/ _jsx(Divider, {}),
|
|
95
|
+
runningProcesses.map((item)=>/*#__PURE__*/ _jsx(CompactProcessLine, {
|
|
96
|
+
item: item
|
|
97
|
+
}, item.id)),
|
|
98
|
+
processes.length > 0 && /*#__PURE__*/ _jsxs(_Fragment, {
|
|
99
|
+
children: [
|
|
100
|
+
/*#__PURE__*/ _jsx(Divider, {}),
|
|
101
|
+
/*#__PURE__*/ _jsx(StatusBar, {
|
|
102
|
+
running: runningCount,
|
|
103
|
+
done: doneCount,
|
|
104
|
+
errors: errorCount,
|
|
105
|
+
errorLines: errorLineCount
|
|
106
|
+
})
|
|
107
|
+
]
|
|
108
|
+
})
|
|
109
|
+
]
|
|
25
110
|
});
|
|
26
111
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/node/spawn-term/src/components/App.tsx"],"sourcesContent":["import { Box, useApp } from 'ink';\nimport { useEffect, useSyncExternalStore } from 'react';\nimport { processStore } from '../state/processStore.ts';\nimport
|
|
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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"}
|