@pokit/tabs-core 0.0.39 → 0.0.42
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.
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"process-manager.d.ts","sourceRoot":"","sources":["../src/process-manager.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"process-manager.d.ts","sourceRoot":"","sources":["../src/process-manager.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAWxD,eAAO,MAAM,eAAe,KAAK,CAAC;AAMlC;;;GAGG;AACH,MAAM,MAAM,OAAO,GAAG;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,uBAAuB,GAAG;IACpC,2DAA2D;IAC3D,cAAc,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IACzD,2CAA2C;IAC3C,cAAc,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,QAAQ,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IAC9E,gDAAgD;IAChD,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACjD,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG;IAClC,qCAAqC;IACrC,GAAG,EAAE,MAAM,CAAC;IACZ,yCAAyC;IACzC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;IACxC,kCAAkC;IAClC,SAAS,EAAE,uBAAuB,CAAC;CACpC,CAAC;AAUF;;;;;;;GAOG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,KAAK,CAAY;IACzB,OAAO,CAAC,OAAO,CAAwB;IACvC,OAAO,CAAC,SAAS,CAA+B;IAChD,OAAO,CAAC,aAAa,CAAwC;IAC7D,OAAO,CAAC,aAAa,CAAqB;IAC1C,OAAO,CAAC,cAAc,CAAS;IAC/B,OAAO,CAAC,SAAS,CAAS;gBAEd,KAAK,EAAE,OAAO,EAAE,EAAE,OAAO,EAAE,qBAAqB;IAM5D;;OAEG;IACH,cAAc,IAAI,UAAU,EAAE;IAU9B;;OAEG;IACH,KAAK,IAAI,IAAI;IAQb;;OAEG;IACH,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IA4B5B;;OAEG;IACH,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAWzB;;OAEG;IACH,OAAO,IAAI,IAAI;IASf;;OAEG;IACH,OAAO,IAAI,IAAI;IAUf,OAAO,CAAC,YAAY;IAwCpB,OAAO,CAAC,YAAY;IAkBpB,OAAO,CAAC,aAAa;IAMrB,OAAO,CAAC,WAAW;CAcpB"}
|
package/dist/process-manager.js
CHANGED
|
@@ -5,6 +5,16 @@
|
|
|
5
5
|
* Framework-agnostic - provides callbacks for UI frameworks to consume.
|
|
6
6
|
*/
|
|
7
7
|
import { spawn } from 'node:child_process';
|
|
8
|
+
function killProcessTree(proc) {
|
|
9
|
+
if (proc.killed || proc.pid == null)
|
|
10
|
+
return;
|
|
11
|
+
try {
|
|
12
|
+
process.kill(-proc.pid, 'SIGTERM');
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
// Process may have already exited
|
|
16
|
+
}
|
|
17
|
+
}
|
|
8
18
|
export const OUTPUT_BATCH_MS = 16;
|
|
9
19
|
// =============================================================================
|
|
10
20
|
// ProcessManager Class
|
|
@@ -22,6 +32,7 @@ export class ProcessManager {
|
|
|
22
32
|
options;
|
|
23
33
|
processes = [];
|
|
24
34
|
outputBuffers = new Map();
|
|
35
|
+
expectedStops = new Set();
|
|
25
36
|
flushScheduled = false;
|
|
26
37
|
destroyed = false;
|
|
27
38
|
constructor(items, options) {
|
|
@@ -62,8 +73,9 @@ export class ProcessManager {
|
|
|
62
73
|
return;
|
|
63
74
|
// Kill existing process
|
|
64
75
|
const existingProc = this.processes[index];
|
|
65
|
-
if (existingProc
|
|
66
|
-
|
|
76
|
+
if (existingProc) {
|
|
77
|
+
this.expectedStops.add(index);
|
|
78
|
+
killProcessTree(existingProc);
|
|
67
79
|
}
|
|
68
80
|
// Clear output buffer
|
|
69
81
|
this.outputBuffers.delete(index);
|
|
@@ -82,8 +94,9 @@ export class ProcessManager {
|
|
|
82
94
|
*/
|
|
83
95
|
kill(index) {
|
|
84
96
|
const proc = this.processes[index];
|
|
85
|
-
if (proc
|
|
86
|
-
|
|
97
|
+
if (proc) {
|
|
98
|
+
this.expectedStops.add(index);
|
|
99
|
+
killProcessTree(proc);
|
|
87
100
|
}
|
|
88
101
|
this.options.callbacks.onOutputUpdate(index, ['', 'Stopped']);
|
|
89
102
|
this.options.callbacks.onStatusChange(index, 'stopped');
|
|
@@ -92,9 +105,10 @@ export class ProcessManager {
|
|
|
92
105
|
* Kill all processes
|
|
93
106
|
*/
|
|
94
107
|
killAll() {
|
|
95
|
-
for (const proc of this.processes) {
|
|
96
|
-
if (proc
|
|
97
|
-
|
|
108
|
+
for (const [index, proc] of this.processes.entries()) {
|
|
109
|
+
if (proc) {
|
|
110
|
+
this.expectedStops.add(index);
|
|
111
|
+
killProcessTree(proc);
|
|
98
112
|
}
|
|
99
113
|
}
|
|
100
114
|
}
|
|
@@ -120,6 +134,7 @@ export class ProcessManager {
|
|
|
120
134
|
FORCE_COLOR: '1',
|
|
121
135
|
},
|
|
122
136
|
stdio: ['inherit', 'pipe', 'pipe'],
|
|
137
|
+
detached: true,
|
|
123
138
|
});
|
|
124
139
|
this.processes[index] = proc;
|
|
125
140
|
const handleData = (data) => this.appendOutput(index, data);
|
|
@@ -127,6 +142,11 @@ export class ProcessManager {
|
|
|
127
142
|
proc.stderr?.on('data', handleData);
|
|
128
143
|
proc.on('close', (code) => {
|
|
129
144
|
this.flushOutput();
|
|
145
|
+
this.processes[index] = null;
|
|
146
|
+
// Ignore close transitions for intentional stops (kill/restart/destroy).
|
|
147
|
+
if (this.expectedStops.delete(index)) {
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
130
150
|
const status = code === 0 ? 'done' : 'error';
|
|
131
151
|
this.options.callbacks.onStatusChange(index, status, code ?? undefined);
|
|
132
152
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pokit/tabs-core",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.42",
|
|
4
4
|
"description": "Core tab management utilities for pok CLI applications",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cli",
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
},
|
|
46
46
|
"peerDependencies": {
|
|
47
47
|
"react": "^18.0.0 || ^19.0.0",
|
|
48
|
-
"@pokit/core": "0.0.
|
|
48
|
+
"@pokit/core": "0.0.42"
|
|
49
49
|
},
|
|
50
50
|
"peerDependenciesMeta": {
|
|
51
51
|
"react": {
|
|
@@ -56,7 +56,7 @@
|
|
|
56
56
|
"@types/bun": "latest",
|
|
57
57
|
"@types/react": "^19.2.0",
|
|
58
58
|
"react": "^19.2.0",
|
|
59
|
-
"@pokit/core": "0.0.
|
|
59
|
+
"@pokit/core": "0.0.42"
|
|
60
60
|
},
|
|
61
61
|
"engines": {
|
|
62
62
|
"bun": ">=1.0.0"
|
package/src/process-manager.ts
CHANGED
|
@@ -8,6 +8,15 @@
|
|
|
8
8
|
import { spawn, type ChildProcess } from 'node:child_process';
|
|
9
9
|
import type { TabStatus, TabProcess } from './types.js';
|
|
10
10
|
|
|
11
|
+
function killProcessTree(proc: ChildProcess): void {
|
|
12
|
+
if (proc.killed || proc.pid == null) return;
|
|
13
|
+
try {
|
|
14
|
+
process.kill(-proc.pid, 'SIGTERM');
|
|
15
|
+
} catch {
|
|
16
|
+
// Process may have already exited
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
11
20
|
export const OUTPUT_BATCH_MS = 16;
|
|
12
21
|
|
|
13
22
|
// =============================================================================
|
|
@@ -62,6 +71,7 @@ export class ProcessManager {
|
|
|
62
71
|
private options: ProcessManagerOptions;
|
|
63
72
|
private processes: (ChildProcess | null)[] = [];
|
|
64
73
|
private outputBuffers: Map<number, OutputBuffer> = new Map();
|
|
74
|
+
private expectedStops = new Set<number>();
|
|
65
75
|
private flushScheduled = false;
|
|
66
76
|
private destroyed = false;
|
|
67
77
|
|
|
@@ -106,8 +116,9 @@ export class ProcessManager {
|
|
|
106
116
|
|
|
107
117
|
// Kill existing process
|
|
108
118
|
const existingProc = this.processes[index];
|
|
109
|
-
if (existingProc
|
|
110
|
-
|
|
119
|
+
if (existingProc) {
|
|
120
|
+
this.expectedStops.add(index);
|
|
121
|
+
killProcessTree(existingProc);
|
|
111
122
|
}
|
|
112
123
|
|
|
113
124
|
// Clear output buffer
|
|
@@ -130,8 +141,9 @@ export class ProcessManager {
|
|
|
130
141
|
*/
|
|
131
142
|
kill(index: number): void {
|
|
132
143
|
const proc = this.processes[index];
|
|
133
|
-
if (proc
|
|
134
|
-
|
|
144
|
+
if (proc) {
|
|
145
|
+
this.expectedStops.add(index);
|
|
146
|
+
killProcessTree(proc);
|
|
135
147
|
}
|
|
136
148
|
|
|
137
149
|
this.options.callbacks.onOutputUpdate(index, ['', 'Stopped']);
|
|
@@ -142,9 +154,10 @@ export class ProcessManager {
|
|
|
142
154
|
* Kill all processes
|
|
143
155
|
*/
|
|
144
156
|
killAll(): void {
|
|
145
|
-
for (const proc of this.processes) {
|
|
146
|
-
if (proc
|
|
147
|
-
|
|
157
|
+
for (const [index, proc] of this.processes.entries()) {
|
|
158
|
+
if (proc) {
|
|
159
|
+
this.expectedStops.add(index);
|
|
160
|
+
killProcessTree(proc);
|
|
148
161
|
}
|
|
149
162
|
}
|
|
150
163
|
}
|
|
@@ -173,6 +186,7 @@ export class ProcessManager {
|
|
|
173
186
|
FORCE_COLOR: '1',
|
|
174
187
|
} as NodeJS.ProcessEnv,
|
|
175
188
|
stdio: ['inherit', 'pipe', 'pipe'],
|
|
189
|
+
detached: true,
|
|
176
190
|
});
|
|
177
191
|
|
|
178
192
|
this.processes[index] = proc;
|
|
@@ -184,6 +198,13 @@ export class ProcessManager {
|
|
|
184
198
|
|
|
185
199
|
proc.on('close', (code) => {
|
|
186
200
|
this.flushOutput();
|
|
201
|
+
this.processes[index] = null;
|
|
202
|
+
|
|
203
|
+
// Ignore close transitions for intentional stops (kill/restart/destroy).
|
|
204
|
+
if (this.expectedStops.delete(index)) {
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
|
|
187
208
|
const status: TabStatus = code === 0 ? 'done' : 'error';
|
|
188
209
|
this.options.callbacks.onStatusChange(index, status, code ?? undefined);
|
|
189
210
|
});
|