@aliou/pi-processes 0.9.4 → 0.10.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.
Files changed (171) hide show
  1. package/CONTRIBUTING.md +40 -42
  2. package/README.md +54 -84
  3. package/extensions/process-tabs.ts +26 -0
  4. package/extensions/processes/client.ts +194 -0
  5. package/extensions/processes/commands/clear.ts +29 -0
  6. package/extensions/processes/commands/kill.ts +152 -0
  7. package/extensions/processes/commands/overview.ts +102 -0
  8. package/extensions/processes/components/overview-component.ts +729 -0
  9. package/extensions/processes/components/overview-panel.ts +177 -0
  10. package/extensions/processes/config/defaults.ts +28 -0
  11. package/extensions/processes/config/index.ts +13 -0
  12. package/extensions/processes/config/loader.ts +62 -0
  13. package/extensions/processes/config/migrations/000-import-legacy-process-config.ts +113 -0
  14. package/extensions/processes/config/migrations/001-v0-9-4-to-v0-10-0-config.ts +184 -0
  15. package/extensions/processes/config/migrations/002-stamp-v0-10-0-config-version.ts +21 -0
  16. package/extensions/processes/config/migrations/index.ts +25 -0
  17. package/extensions/processes/config/schema.ts +9 -0
  18. package/extensions/processes/config/types.ts +72 -0
  19. package/extensions/processes/constants.ts +1 -0
  20. package/extensions/processes/handlers/commands.ts +113 -0
  21. package/extensions/processes/handlers/kill-process.ts +31 -0
  22. package/extensions/processes/handlers/notifications.ts +147 -0
  23. package/extensions/processes/handlers/requests.ts +114 -0
  24. package/extensions/processes/handlers/subscriptions.ts +144 -0
  25. package/extensions/processes/hooks/background-blocker.ts +201 -0
  26. package/extensions/processes/hooks/cleanup.ts +43 -0
  27. package/extensions/processes/hooks/event-bridge.ts +32 -0
  28. package/extensions/processes/i18n/index.ts +3 -0
  29. package/extensions/processes/i18n/messages.ts +27 -0
  30. package/extensions/processes/i18n/translator.ts +49 -0
  31. package/extensions/processes/index.ts +109 -0
  32. package/extensions/processes/message-renderer.ts +117 -0
  33. package/extensions/processes/notification-sender.ts +43 -0
  34. package/extensions/processes/notifications/classify.ts +27 -0
  35. package/extensions/processes/notifications/log-matchers.ts +146 -0
  36. package/extensions/processes/notifications/registry.ts +225 -0
  37. package/extensions/processes/notifications/render-content.ts +122 -0
  38. package/extensions/processes/notifications/service.ts +336 -0
  39. package/extensions/processes/notifications/types.ts +11 -0
  40. package/extensions/processes/settings/apply-setting-change.ts +30 -0
  41. package/extensions/processes/settings/build-sections.ts +420 -0
  42. package/extensions/processes/settings/index.ts +42 -0
  43. package/extensions/processes/tools/clear/index.ts +21 -0
  44. package/extensions/processes/tools/clear/render.ts +40 -0
  45. package/extensions/processes/tools/components/index.ts +4 -0
  46. package/extensions/processes/tools/components/process-action-header.ts +31 -0
  47. package/extensions/processes/tools/components/process-action-title.ts +17 -0
  48. package/extensions/processes/tools/components/tool-layout.ts +70 -0
  49. package/extensions/processes/tools/components/watch.ts +53 -0
  50. package/extensions/processes/tools/index.ts +265 -0
  51. package/extensions/processes/tools/list/index.ts +157 -0
  52. package/extensions/processes/tools/list/render.ts +211 -0
  53. package/extensions/processes/tools/notify.ts +191 -0
  54. package/extensions/processes/tools/output/index.ts +307 -0
  55. package/extensions/processes/tools/output/render.ts +229 -0
  56. package/extensions/processes/tools/schema.ts +263 -0
  57. package/extensions/processes/tools/start/index.ts +64 -0
  58. package/extensions/processes/tools/start/render.ts +67 -0
  59. package/extensions/processes/tools/stop/index.ts +35 -0
  60. package/extensions/processes/tools/stop/render.ts +43 -0
  61. package/extensions/processes/tools/update/index.ts +320 -0
  62. package/extensions/processes/tools/update/render.ts +251 -0
  63. package/extensions/processes/tools/utils.ts +112 -0
  64. package/extensions/processes/tools/watch-format.ts +14 -0
  65. package/extensions/processes/tools/write/index.ts +75 -0
  66. package/extensions/processes/tools/write/render.ts +68 -0
  67. package/extensions/processes/utils/truncate.ts +285 -0
  68. package/extensions/processes-dock/client.ts +60 -0
  69. package/extensions/processes-dock/commands/dock.ts +70 -0
  70. package/extensions/processes-dock/commands/pin.ts +166 -0
  71. package/extensions/processes-dock/components/log-dock-component.ts +375 -0
  72. package/extensions/processes-dock/dock-state.ts +33 -0
  73. package/extensions/processes-dock/index.ts +28 -0
  74. package/extensions/processes-dock/logs-client.ts +5 -0
  75. package/extensions/processes-dock/widget/setup.ts +520 -0
  76. package/extensions/processes-dock/widget/status.ts +149 -0
  77. package/extensions/processes-dock/widget/types.ts +16 -0
  78. package/extensions/processes-logs/client.ts +51 -0
  79. package/extensions/processes-logs/commands/logs.ts +108 -0
  80. package/extensions/processes-logs/completions.ts +31 -0
  81. package/extensions/processes-logs/components/log-file-viewer.ts +274 -0
  82. package/extensions/processes-logs/components/log-overlay-component.ts +685 -0
  83. package/extensions/processes-logs/index.ts +27 -0
  84. package/extensions/processes-logs/logs-client.ts +101 -0
  85. package/extensions/shared/line-buffer.ts +35 -0
  86. package/extensions/shared/output-payload.ts +28 -0
  87. package/extensions/shared/ui.ts +146 -0
  88. package/package.json +47 -20
  89. package/schema.json +134 -0
  90. package/skills/pi-processes/SKILL.md +496 -25
  91. package/src/get-manager.ts +15 -0
  92. package/src/manager/index.ts +182 -0
  93. package/src/manager/internal-types.ts +130 -0
  94. package/src/manager/limits.ts +15 -0
  95. package/src/manager/process-log-store.ts +422 -0
  96. package/src/manager/process-output.ts +345 -0
  97. package/src/manager/process-registry.ts +78 -0
  98. package/src/manager/process-runtime-controller.ts +499 -0
  99. package/src/protocol/broadcasts.ts +14 -0
  100. package/src/protocol/channels.ts +30 -0
  101. package/src/protocol/commands.ts +24 -0
  102. package/src/protocol/index.ts +34 -0
  103. package/src/protocol/logs.ts +23 -0
  104. package/src/protocol/notifications.ts +48 -0
  105. package/src/protocol/requests.ts +76 -0
  106. package/src/types.ts +66 -0
  107. package/src/utils/ansi.ts +2 -4
  108. package/src/utils/format.ts +24 -32
  109. package/src/utils/index.ts +5 -1
  110. package/src/utils/is-record.ts +3 -0
  111. package/src/utils/match-line.ts +32 -0
  112. package/src/utils/platform.ts +13 -0
  113. package/src/utils/shorten-path.ts +11 -0
  114. package/src/utils/signals.ts +22 -0
  115. package/src/commands/clear/command.ts +0 -14
  116. package/src/commands/clear/index.ts +0 -1
  117. package/src/commands/completions.ts +0 -38
  118. package/src/commands/dock/command.ts +0 -29
  119. package/src/commands/dock/index.ts +0 -1
  120. package/src/commands/index.ts +0 -33
  121. package/src/commands/kill/command.ts +0 -69
  122. package/src/commands/kill/index.ts +0 -1
  123. package/src/commands/logs/command.ts +0 -47
  124. package/src/commands/logs/index.ts +0 -1
  125. package/src/commands/pick-process.ts +0 -34
  126. package/src/commands/pin/command.ts +0 -34
  127. package/src/commands/pin/index.ts +0 -1
  128. package/src/commands/processes/command.ts +0 -39
  129. package/src/commands/processes/index.ts +0 -1
  130. package/src/commands/settings/apply-setting-change.ts +0 -72
  131. package/src/commands/settings/build-sections.ts +0 -160
  132. package/src/commands/settings/command.ts +0 -20
  133. package/src/commands/settings/index.ts +0 -1
  134. package/src/components/log-dock-component.test.ts +0 -29
  135. package/src/components/log-dock-component.ts +0 -236
  136. package/src/components/log-file-viewer.ts +0 -317
  137. package/src/components/log-overlay-component.ts +0 -546
  138. package/src/components/panel-helpers.ts +0 -37
  139. package/src/components/process-picker-component.ts +0 -166
  140. package/src/components/processes-component.ts +0 -485
  141. package/src/components/status-format.ts +0 -38
  142. package/src/config.ts +0 -107
  143. package/src/constants/index.ts +0 -16
  144. package/src/constants/types.ts +0 -106
  145. package/src/hooks/background-blocker.ts +0 -66
  146. package/src/hooks/cleanup.ts +0 -10
  147. package/src/hooks/index.ts +0 -32
  148. package/src/hooks/message-renderer.ts +0 -115
  149. package/src/hooks/process-end.ts +0 -69
  150. package/src/hooks/process-watch.ts +0 -85
  151. package/src/hooks/utils.ts +0 -23
  152. package/src/hooks/widget/index.ts +0 -2
  153. package/src/hooks/widget/setup.ts +0 -167
  154. package/src/hooks/widget/status-widget.ts +0 -105
  155. package/src/hooks/widget/types.ts +0 -20
  156. package/src/index.ts +0 -35
  157. package/src/manager.test.ts +0 -331
  158. package/src/manager.ts +0 -758
  159. package/src/tools/actions/clear.ts +0 -20
  160. package/src/tools/actions/debug.ts +0 -148
  161. package/src/tools/actions/index.ts +0 -171
  162. package/src/tools/actions/kill.ts +0 -89
  163. package/src/tools/actions/list.ts +0 -188
  164. package/src/tools/actions/logs.ts +0 -117
  165. package/src/tools/actions/output.ts +0 -269
  166. package/src/tools/actions/start.ts +0 -245
  167. package/src/tools/actions/write.ts +0 -113
  168. package/src/tools/index.ts +0 -207
  169. package/src/utils/ansi.test.ts +0 -22
  170. package/src/utils/command-executor.test.ts +0 -48
  171. package/src/utils/keybindings.ts +0 -71
@@ -0,0 +1,345 @@
1
+ import type { ManagerEvent } from "../types";
2
+ import type { ManagedProcessRecord } from "./internal-types";
3
+ import {
4
+ MAX_LINE_BYTES,
5
+ MAX_LINES_PER_EMIT,
6
+ MAX_PENDING_LINE_BYTES,
7
+ TRUNCATION_SUFFIX,
8
+ } from "./limits";
9
+ import type { ProcessLogStore } from "./process-log-store";
10
+
11
+ interface ProcessOutputDeps {
12
+ emit: (event: ManagerEvent) => void;
13
+ logStore: ProcessLogStore;
14
+ throttleMs?: number;
15
+ }
16
+
17
+ export class ProcessOutput {
18
+ private emit: (event: ManagerEvent) => void;
19
+ private logStore: ProcessLogStore;
20
+ private throttleMs: number;
21
+
22
+ private lastOutputEmitAt: Map<string, number> = new Map();
23
+ private pendingOutputEmit: Map<string, NodeJS.Timeout> = new Map();
24
+
25
+ constructor(deps: ProcessOutputDeps) {
26
+ this.emit = deps.emit;
27
+ this.logStore = deps.logStore;
28
+ this.throttleMs = deps.throttleMs ?? 100;
29
+ }
30
+
31
+ onStdoutChunk(record: ManagedProcessRecord, data: Buffer): string[] {
32
+ return this.extractCompleteLines(record, "stdout", data, (line) => {
33
+ this.logStore.appendCombinedLine(record.combinedFile, "stdout", line);
34
+ this.appendEventLine(record, "stdout", line);
35
+ });
36
+ }
37
+
38
+ onStderrChunk(record: ManagedProcessRecord, data: Buffer): string[] {
39
+ return this.extractCompleteLines(record, "stderr", data, (line) => {
40
+ this.logStore.appendCombinedLine(record.combinedFile, "stderr", line);
41
+ this.appendEventLine(record, "stderr", line);
42
+ });
43
+ }
44
+
45
+ flush(record: ManagedProcessRecord): void {
46
+ this.flushPendingLines(record);
47
+ this.trimEventBuffer(record);
48
+
49
+ const timeout = this.pendingOutputEmit.get(record.id);
50
+ if (timeout) {
51
+ clearTimeout(timeout);
52
+ this.pendingOutputEmit.delete(record.id);
53
+ }
54
+
55
+ const drained = this.drainAppendedLines(record);
56
+ if (!timeout && !drained) return;
57
+
58
+ this.lastOutputEmitAt.set(record.id, Date.now());
59
+ this.emit({
60
+ type: "process_output_changed",
61
+ id: record.id,
62
+ ...(drained?.appendedText ? { appendedText: drained.appendedText } : {}),
63
+ ...(drained?.droppedLines ? { droppedLines: drained.droppedLines } : {}),
64
+ });
65
+ }
66
+
67
+ clear(id: string): void {
68
+ const timeout = this.pendingOutputEmit.get(id);
69
+ if (timeout) clearTimeout(timeout);
70
+ this.pendingOutputEmit.delete(id);
71
+ this.lastOutputEmitAt.delete(id);
72
+ }
73
+
74
+ clearAll(): void {
75
+ for (const timeout of this.pendingOutputEmit.values()) {
76
+ clearTimeout(timeout);
77
+ }
78
+ this.pendingOutputEmit.clear();
79
+ this.lastOutputEmitAt.clear();
80
+ }
81
+
82
+ private notify(record: ManagedProcessRecord): void {
83
+ this.trimEventBuffer(record);
84
+ const now = Date.now();
85
+ const lastEmit = this.lastOutputEmitAt.get(record.id) ?? 0;
86
+ const elapsed = now - lastEmit;
87
+
88
+ if (elapsed >= this.throttleMs) {
89
+ this.lastOutputEmitAt.set(record.id, now);
90
+ const drained = this.drainAppendedLines(record);
91
+ this.emit({
92
+ type: "process_output_changed",
93
+ id: record.id,
94
+ ...(drained?.appendedText
95
+ ? { appendedText: drained.appendedText }
96
+ : {}),
97
+ ...(drained?.droppedLines
98
+ ? { droppedLines: drained.droppedLines }
99
+ : {}),
100
+ });
101
+ return;
102
+ }
103
+
104
+ if (!this.pendingOutputEmit.has(record.id)) {
105
+ const delay = this.throttleMs - elapsed;
106
+ const timeout = setTimeout(() => {
107
+ this.pendingOutputEmit.delete(record.id);
108
+ const drained = this.drainAppendedLines(record);
109
+ if (!drained) return;
110
+ this.lastOutputEmitAt.set(record.id, Date.now());
111
+ this.emit({
112
+ type: "process_output_changed",
113
+ id: record.id,
114
+ ...(drained.appendedText
115
+ ? { appendedText: drained.appendedText }
116
+ : {}),
117
+ ...(drained.droppedLines
118
+ ? { droppedLines: drained.droppedLines }
119
+ : {}),
120
+ });
121
+ }, delay);
122
+ this.pendingOutputEmit.set(record.id, timeout);
123
+ }
124
+ }
125
+
126
+ private flushPendingLines(record: ManagedProcessRecord): void {
127
+ if (record.stdoutPendingLine.length > 0) {
128
+ const line = record.stdoutPendingLine.toString("utf-8");
129
+ this.logStore.appendCombinedLine(record.combinedFile, "stdout", line);
130
+ this.appendEventLine(record, "stdout", line);
131
+ }
132
+ record.stdoutPendingLine = Buffer.alloc(0);
133
+ record.stdoutLineOverflowed = false;
134
+
135
+ if (record.stderrPendingLine.length > 0) {
136
+ const line = record.stderrPendingLine.toString("utf-8");
137
+ this.logStore.appendCombinedLine(record.combinedFile, "stderr", line);
138
+ this.appendEventLine(record, "stderr", line);
139
+ }
140
+ record.stderrPendingLine = Buffer.alloc(0);
141
+ record.stderrLineOverflowed = false;
142
+ }
143
+
144
+ private drainAppendedLines(record: ManagedProcessRecord):
145
+ | {
146
+ appendedText?: Array<{
147
+ type: "stdout" | "stderr";
148
+ text: string;
149
+ }>;
150
+ droppedLines?: number;
151
+ }
152
+ | undefined {
153
+ if (record.appendedLines.length === 0 && record.droppedLineCount === 0) {
154
+ return undefined;
155
+ }
156
+ const lines = record.appendedLines;
157
+ const droppedLines = record.droppedLineCount;
158
+ record.appendedLines = [];
159
+ record.droppedLineCount = 0;
160
+ return {
161
+ ...(lines.length > 0 ? { appendedText: lines } : {}),
162
+ ...(droppedLines > 0 ? { droppedLines } : {}),
163
+ };
164
+ }
165
+
166
+ private extractCompleteLines(
167
+ record: ManagedProcessRecord,
168
+ source: "stdout" | "stderr",
169
+ data: Buffer,
170
+ onLine: (line: string) => void,
171
+ ): string[] {
172
+ let pending = this.getPending(record, source);
173
+ let overflowed = this.getOverflowed(record, source);
174
+ const completeLines: string[] = [];
175
+ let cursor = 0;
176
+
177
+ if (overflowed) {
178
+ const newline = data.indexOf(0x0a);
179
+ if (newline === -1) {
180
+ this.notify(record);
181
+ return [];
182
+ }
183
+ cursor = newline + 1;
184
+ overflowed = false;
185
+ pending = Buffer.alloc(0);
186
+ }
187
+
188
+ let newline = data.indexOf(0x0a, cursor);
189
+ while (newline !== -1) {
190
+ const line = this.buildBoundedLine(
191
+ pending,
192
+ data.subarray(cursor, newline),
193
+ true,
194
+ );
195
+ onLine(line);
196
+ if (completeLines.length < MAX_LINES_PER_EMIT) completeLines.push(line);
197
+ pending = Buffer.alloc(0);
198
+ cursor = newline + 1;
199
+ newline = data.indexOf(0x0a, cursor);
200
+ }
201
+
202
+ const tail = data.subarray(cursor);
203
+ const tailLength = tail.length;
204
+ if (pending.length + tailLength > MAX_PENDING_LINE_BYTES) {
205
+ const line = this.buildBoundedLine(pending, tail, false);
206
+ onLine(line);
207
+ if (completeLines.length < MAX_LINES_PER_EMIT) completeLines.push(line);
208
+ pending = Buffer.alloc(0);
209
+ overflowed = true;
210
+ // The raw stdout/stderr log still has the complete bytes. Dropping the
211
+ // event-stream tail avoids turning one huge logical line into thousands
212
+ // of synthetic lines in UI buffers.
213
+ } else {
214
+ pending =
215
+ pending.length === 0
216
+ ? Buffer.from(tail)
217
+ : Buffer.concat([pending, tail], pending.length + tail.length);
218
+ }
219
+
220
+ this.setPending(record, source, pending);
221
+ this.setOverflowed(record, source, overflowed);
222
+ this.notify(record);
223
+ return completeLines;
224
+ }
225
+
226
+ private buildBoundedLine(
227
+ pending: Buffer,
228
+ segment: Buffer,
229
+ stripCarriageReturn: boolean,
230
+ ): string {
231
+ let pendingEnd = pending.length;
232
+ let segmentEnd = segment.length;
233
+ if (stripCarriageReturn) {
234
+ if (segmentEnd > 0 && segment[segmentEnd - 1] === 0x0d) segmentEnd--;
235
+ else if (
236
+ segmentEnd === 0 &&
237
+ pendingEnd > 0 &&
238
+ pending[pendingEnd - 1] === 0x0d
239
+ ) {
240
+ pendingEnd--;
241
+ }
242
+ }
243
+
244
+ const totalLength = pendingEnd + segmentEnd;
245
+ if (totalLength <= MAX_PENDING_LINE_BYTES) {
246
+ return Buffer.concat(
247
+ [pending.subarray(0, pendingEnd), segment.subarray(0, segmentEnd)],
248
+ totalLength,
249
+ ).toString("utf-8");
250
+ }
251
+
252
+ const prefix = Buffer.allocUnsafe(MAX_PENDING_LINE_BYTES);
253
+ const pendingLength = Math.min(pendingEnd, MAX_PENDING_LINE_BYTES);
254
+ pending.copy(prefix, 0, 0, pendingLength);
255
+ const segmentLength = MAX_PENDING_LINE_BYTES - pendingLength;
256
+ segment.copy(prefix, pendingLength, 0, segmentLength);
257
+ return `${trimIncompleteUtf8Suffix(prefix).toString("utf-8")}${TRUNCATION_SUFFIX}`;
258
+ }
259
+
260
+ private appendEventLine(
261
+ record: ManagedProcessRecord,
262
+ type: "stdout" | "stderr",
263
+ text: string,
264
+ ): void {
265
+ record.appendedLines.push({ type, text: this.clampLine(text) });
266
+ if (record.appendedLines.length <= MAX_LINES_PER_EMIT * 2) return;
267
+ this.trimEventBuffer(record);
268
+ }
269
+
270
+ private trimEventBuffer(record: ManagedProcessRecord): void {
271
+ if (record.appendedLines.length <= MAX_LINES_PER_EMIT) return;
272
+ const overflow = record.appendedLines.length - MAX_LINES_PER_EMIT;
273
+ record.appendedLines.splice(0, overflow);
274
+ record.droppedLineCount += overflow;
275
+ }
276
+
277
+ private clampLine(text: string): string {
278
+ if (Buffer.byteLength(text) <= MAX_LINE_BYTES) return text;
279
+ const suffixBytes = Buffer.byteLength(TRUNCATION_SUFFIX);
280
+ const prefix = Buffer.from(text).subarray(0, MAX_LINE_BYTES - suffixBytes);
281
+ return `${trimIncompleteUtf8Suffix(prefix).toString("utf-8")}${TRUNCATION_SUFFIX}`;
282
+ }
283
+
284
+ private getPending(
285
+ record: ManagedProcessRecord,
286
+ source: "stdout" | "stderr",
287
+ ): Buffer {
288
+ return source === "stdout"
289
+ ? record.stdoutPendingLine
290
+ : record.stderrPendingLine;
291
+ }
292
+
293
+ private setPending(
294
+ record: ManagedProcessRecord,
295
+ source: "stdout" | "stderr",
296
+ value: Buffer,
297
+ ): void {
298
+ if (source === "stdout") record.stdoutPendingLine = value;
299
+ else record.stderrPendingLine = value;
300
+ }
301
+
302
+ private getOverflowed(
303
+ record: ManagedProcessRecord,
304
+ source: "stdout" | "stderr",
305
+ ): boolean {
306
+ return source === "stdout"
307
+ ? record.stdoutLineOverflowed
308
+ : record.stderrLineOverflowed;
309
+ }
310
+
311
+ private setOverflowed(
312
+ record: ManagedProcessRecord,
313
+ source: "stdout" | "stderr",
314
+ value: boolean,
315
+ ): void {
316
+ if (source === "stdout") record.stdoutLineOverflowed = value;
317
+ else record.stderrLineOverflowed = value;
318
+ }
319
+
320
+ [Symbol.dispose](): void {
321
+ this.clearAll();
322
+ }
323
+ }
324
+
325
+ function trimIncompleteUtf8Suffix(buffer: Buffer): Buffer {
326
+ if (buffer.length === 0) return buffer;
327
+
328
+ let lead = buffer.length - 1;
329
+ while (lead >= 0 && (buffer[lead] & 0xc0) === 0x80) lead--;
330
+ if (lead < 0) return Buffer.alloc(0);
331
+
332
+ const leadByte = buffer[lead];
333
+ const expectedLength =
334
+ leadByte < 0x80
335
+ ? 1
336
+ : (leadByte & 0xe0) === 0xc0
337
+ ? 2
338
+ : (leadByte & 0xf0) === 0xe0
339
+ ? 3
340
+ : (leadByte & 0xf8) === 0xf0
341
+ ? 4
342
+ : 1;
343
+ const actualLength = buffer.length - lead;
344
+ return actualLength < expectedLength ? buffer.subarray(0, lead) : buffer;
345
+ }
@@ -0,0 +1,78 @@
1
+ import { randomBytes } from "node:crypto";
2
+
3
+ import { LIVE_STATUSES, type ProcessInfo } from "../types";
4
+ import type { ManagedProcessRecord } from "./internal-types";
5
+ import { formatProcess } from "./internal-types";
6
+
7
+ export class ProcessRegistry {
8
+ private processes: Map<string, ManagedProcessRecord> = new Map();
9
+
10
+ nextId(): string {
11
+ let id: string;
12
+ do {
13
+ id = `proc_${randomBytes(2).toString("hex")}`;
14
+ } while (this.processes.has(id));
15
+ return id;
16
+ }
17
+
18
+ add(process: ManagedProcessRecord): void {
19
+ this.processes.set(process.id, process);
20
+ }
21
+
22
+ getRecord(id: string): ManagedProcessRecord | undefined {
23
+ return this.processes.get(id);
24
+ }
25
+
26
+ getPublicInfo(id: string): ProcessInfo | null {
27
+ const managed = this.processes.get(id);
28
+ return managed ? formatProcess(managed) : null;
29
+ }
30
+
31
+ rename(id: string, name: string): ProcessInfo | null {
32
+ const managed = this.processes.get(id);
33
+ if (!managed) return null;
34
+ managed.name = name;
35
+ return formatProcess(managed);
36
+ }
37
+
38
+ delete(id: string): boolean {
39
+ return this.processes.delete(id);
40
+ }
41
+
42
+ list(): ProcessInfo[] {
43
+ return Array.from(this.processes.values()).map((p) => formatProcess(p));
44
+ }
45
+
46
+ values(): IterableIterator<ManagedProcessRecord> {
47
+ return this.processes.values();
48
+ }
49
+
50
+ entries(): IterableIterator<[string, ManagedProcessRecord]> {
51
+ return this.processes.entries();
52
+ }
53
+
54
+ has(id: string): boolean {
55
+ return this.processes.has(id);
56
+ }
57
+
58
+ hasAliveishProcesses(): boolean {
59
+ for (const p of this.processes.values()) {
60
+ if (LIVE_STATUSES.has(p.status)) return true;
61
+ }
62
+ return false;
63
+ }
64
+
65
+ forEachAlive(
66
+ callback: (id: string, managed: ManagedProcessRecord) => void,
67
+ ): void {
68
+ for (const [id, managed] of this.processes) {
69
+ if (LIVE_STATUSES.has(managed.status)) {
70
+ callback(id, managed);
71
+ }
72
+ }
73
+ }
74
+
75
+ [Symbol.dispose](): void {
76
+ this.processes.clear();
77
+ }
78
+ }