@schoolai/shipyard 3.7.0 → 3.8.0-rc.20260529.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 (104) hide show
  1. package/dist/{auth-SS7LV5XK.js → auth-EXHO3AG5.js} +4 -4
  2. package/dist/capability-detector-worker.js +142 -0
  3. package/dist/capability-detector-worker.js.map +1 -0
  4. package/dist/{chunk-DKMDBOFU.js → chunk-2CNIEBKO.js} +21 -11
  5. package/dist/chunk-2CNIEBKO.js.map +1 -0
  6. package/dist/chunk-4T2OQAVL.js +51 -0
  7. package/dist/chunk-4T2OQAVL.js.map +1 -0
  8. package/dist/chunk-5ER6ZHA2.js +46 -0
  9. package/dist/chunk-5ER6ZHA2.js.map +1 -0
  10. package/dist/chunk-7LSEE26O.js +24227 -0
  11. package/dist/chunk-7LSEE26O.js.map +1 -0
  12. package/dist/{chunk-7AHRFPAL.js → chunk-7YOU7MBN.js} +183 -17
  13. package/dist/chunk-7YOU7MBN.js.map +1 -0
  14. package/dist/chunk-CMGJGK6R.js +382 -0
  15. package/dist/chunk-CMGJGK6R.js.map +1 -0
  16. package/dist/{chunk-VPMN47TL.js → chunk-CNR7O5YH.js} +1 -2
  17. package/dist/{chunk-2J3WSIAF.js → chunk-EF2DAODF.js} +18 -3
  18. package/dist/chunk-EF2DAODF.js.map +1 -0
  19. package/dist/chunk-HQ43PHOH.js +1203 -0
  20. package/dist/chunk-HQ43PHOH.js.map +1 -0
  21. package/dist/chunk-KITSAHTX.js +134 -0
  22. package/dist/chunk-KITSAHTX.js.map +1 -0
  23. package/dist/chunk-LESHN5J5.js +6898 -0
  24. package/dist/chunk-LESHN5J5.js.map +1 -0
  25. package/dist/{chunk-LW2MS4T5.js → chunk-LMJFHKRD.js} +15 -12
  26. package/dist/chunk-LMJFHKRD.js.map +1 -0
  27. package/dist/{chunk-SNYEQHUK.js → chunk-NACJENDW.js} +14 -21
  28. package/dist/chunk-NACJENDW.js.map +1 -0
  29. package/dist/{chunk-IISLTKYY.js → chunk-TU63KZFW.js} +2 -2
  30. package/dist/chunk-TX6DK4PK.js +186 -0
  31. package/dist/chunk-TX6DK4PK.js.map +1 -0
  32. package/dist/chunk-UQVXWOPT.js +48 -0
  33. package/dist/chunk-UQVXWOPT.js.map +1 -0
  34. package/dist/{chunk-3MNPDCO5.js → chunk-WBB4XHLH.js} +139 -140
  35. package/dist/chunk-WBB4XHLH.js.map +1 -0
  36. package/dist/chunk-X3MULCV5.js +11 -0
  37. package/dist/chunk-X3MULCV5.js.map +1 -0
  38. package/dist/chunk-YZ3Z3ZYI.js +787 -0
  39. package/dist/chunk-YZ3Z3ZYI.js.map +1 -0
  40. package/dist/{chunk-2UN5AR7V.js → chunk-ZAOPND5G.js} +2 -2
  41. package/dist/chunk-ZFKJAYAN.js +542 -0
  42. package/dist/chunk-ZFKJAYAN.js.map +1 -0
  43. package/dist/cursor-hook-shim.js +316 -0
  44. package/dist/cursor-hook-shim.js.map +1 -0
  45. package/dist/cursor-runner.js +358 -0
  46. package/dist/cursor-runner.js.map +1 -0
  47. package/dist/electron-utility.js +111 -0
  48. package/dist/electron-utility.js.map +1 -0
  49. package/dist/git-pool-V73Q53NX.js +18 -0
  50. package/dist/{git-repo-VRT57DGC.js → git-repo-TN3VZXQV.js} +9 -6
  51. package/dist/index.js +12 -12
  52. package/dist/index.js.map +1 -1
  53. package/dist/{logger-GQCSLSZH.js → logger-QHPTO22N.js} +4 -4
  54. package/dist/login-Q7SZI7JJ.js +20 -0
  55. package/dist/{logout-VUNCW5B2.js → logout-O4AVMO5S.js} +6 -6
  56. package/dist/mcp-servers-F64M5T4I.js +24 -0
  57. package/dist/{roi-Y3MX5UW4.js → roi-EYDLPOCS.js} +5 -5
  58. package/dist/rss-worker.js +159 -0
  59. package/dist/rss-worker.js.map +1 -0
  60. package/dist/{serve-O53FNK64.js → serve-6A7RJWEF.js} +89862 -102999
  61. package/dist/{serve-O53FNK64.js.map → serve-6A7RJWEF.js.map} +1 -1
  62. package/dist/skills-ZHEPSBHW.js +11 -0
  63. package/dist/{start-IDFDHRD6.js → start-YGYYIK53.js} +229 -27
  64. package/dist/start-YGYYIK53.js.map +1 -0
  65. package/dist/vault-crypto-BKDOA65F.js +13 -0
  66. package/dist/vault-crypto-BKDOA65F.js.map +1 -0
  67. package/dist/worker.js +6 -3
  68. package/dist/worker.js.map +1 -1
  69. package/package.json +17 -10
  70. package/dist/chunk-2J3WSIAF.js.map +0 -1
  71. package/dist/chunk-3MNPDCO5.js.map +0 -1
  72. package/dist/chunk-66OBOZ3X.js +0 -79
  73. package/dist/chunk-66OBOZ3X.js.map +0 -1
  74. package/dist/chunk-7AHRFPAL.js.map +0 -1
  75. package/dist/chunk-DKMDBOFU.js.map +0 -1
  76. package/dist/chunk-L2WQMPWS.js +0 -666
  77. package/dist/chunk-L2WQMPWS.js.map +0 -1
  78. package/dist/chunk-LW2MS4T5.js.map +0 -1
  79. package/dist/chunk-PI77CUEP.js +0 -49
  80. package/dist/chunk-PI77CUEP.js.map +0 -1
  81. package/dist/chunk-RXI4637N.js +0 -395
  82. package/dist/chunk-RXI4637N.js.map +0 -1
  83. package/dist/chunk-SNYEQHUK.js.map +0 -1
  84. package/dist/chunk-VBPHGPBR.js +0 -126
  85. package/dist/chunk-VBPHGPBR.js.map +0 -1
  86. package/dist/index.d.ts +0 -2
  87. package/dist/login-L4BBPUYO.js +0 -20
  88. package/dist/mcp-servers-MXS5VAWI.js +0 -18
  89. package/dist/shell-V36EX2IJ.js +0 -27
  90. package/dist/skills-GPGRNV4R.js +0 -9
  91. package/dist/start-IDFDHRD6.js.map +0 -1
  92. package/dist/worker.d.ts +0 -49
  93. /package/dist/{auth-SS7LV5XK.js.map → auth-EXHO3AG5.js.map} +0 -0
  94. /package/dist/{chunk-VPMN47TL.js.map → chunk-CNR7O5YH.js.map} +0 -0
  95. /package/dist/{chunk-IISLTKYY.js.map → chunk-TU63KZFW.js.map} +0 -0
  96. /package/dist/{chunk-2UN5AR7V.js.map → chunk-ZAOPND5G.js.map} +0 -0
  97. /package/dist/{git-repo-VRT57DGC.js.map → git-pool-V73Q53NX.js.map} +0 -0
  98. /package/dist/{logger-GQCSLSZH.js.map → git-repo-TN3VZXQV.js.map} +0 -0
  99. /package/dist/{login-L4BBPUYO.js.map → logger-QHPTO22N.js.map} +0 -0
  100. /package/dist/{mcp-servers-MXS5VAWI.js.map → login-Q7SZI7JJ.js.map} +0 -0
  101. /package/dist/{logout-VUNCW5B2.js.map → logout-O4AVMO5S.js.map} +0 -0
  102. /package/dist/{shell-V36EX2IJ.js.map → mcp-servers-F64M5T4I.js.map} +0 -0
  103. /package/dist/{roi-Y3MX5UW4.js.map → roi-EYDLPOCS.js.map} +0 -0
  104. /package/dist/{skills-GPGRNV4R.js.map → skills-ZHEPSBHW.js.map} +0 -0
@@ -0,0 +1,542 @@
1
+ #!/usr/bin/env node
2
+
3
+ // ../../packages/local-runtime/src/one-shot-pool.ts
4
+ import { execFile } from "child_process";
5
+ var defaultExecFile = (file, args, opts, cb) => {
6
+ execFile(
7
+ file,
8
+ [...args],
9
+ {
10
+ env: opts.env,
11
+ timeout: opts.timeout,
12
+ maxBuffer: opts.maxBuffer,
13
+ cwd: opts.cwd,
14
+ encoding: "utf8"
15
+ },
16
+ (err, stdout, stderr) => {
17
+ cb(err, stdout, stderr);
18
+ }
19
+ );
20
+ };
21
+ var DEFAULT_MAX_CONCURRENT = 1;
22
+ var DEFAULT_MAX_BUFFER_BYTES = 10 * 1024 * 1024;
23
+ function createOneShotPool(options, deps = {}) {
24
+ const ttlMs = options.ttlMs;
25
+ const maxConcurrent = options.maxConcurrent ?? DEFAULT_MAX_CONCURRENT;
26
+ const execFileImpl = deps.execFile ?? defaultExecFile;
27
+ const now = deps.now ?? (() => Date.now());
28
+ const cache = /* @__PURE__ */ new Map();
29
+ const inFlight = /* @__PURE__ */ new Map();
30
+ const queue = [];
31
+ let activeCount = 0;
32
+ let disposed = false;
33
+ function readCache(key) {
34
+ const entry = cache.get(key);
35
+ if (entry === void 0) return null;
36
+ if (entry.expiresAt <= now()) {
37
+ cache.delete(key);
38
+ return null;
39
+ }
40
+ return entry;
41
+ }
42
+ function writeCache(key, value) {
43
+ if (ttlMs <= 0) return;
44
+ cache.set(key, { value, expiresAt: now() + ttlMs });
45
+ }
46
+ function pumpQueue() {
47
+ while (queue.length > 0 && activeCount < maxConcurrent) {
48
+ const next = queue.shift();
49
+ if (next === void 0) return;
50
+ next.run();
51
+ }
52
+ }
53
+ function runExec(command, options2, cacheKey) {
54
+ activeCount += 1;
55
+ const startedAt = now();
56
+ const [file, ...args] = command;
57
+ if (file === void 0) {
58
+ activeCount -= 1;
59
+ pumpQueue();
60
+ return Promise.reject(new Error("OneShotPool.exec: empty command array"));
61
+ }
62
+ return new Promise((resolve, reject) => {
63
+ execFileImpl(
64
+ file,
65
+ args,
66
+ {
67
+ env: options2?.env,
68
+ timeout: options2?.timeoutMs,
69
+ maxBuffer: options2?.maxBufferBytes ?? DEFAULT_MAX_BUFFER_BYTES,
70
+ cwd: options2?.cwd
71
+ },
72
+ (err, stdout, stderr) => {
73
+ activeCount -= 1;
74
+ if (err !== null) {
75
+ const message = stderr.length > 0 ? `${err.message}: ${stderr}` : err.message;
76
+ const wrapped = new Error(message, { cause: err });
77
+ inFlight.delete(cacheKey);
78
+ pumpQueue();
79
+ reject(wrapped);
80
+ return;
81
+ }
82
+ writeCache(cacheKey, stdout);
83
+ inFlight.delete(cacheKey);
84
+ pumpQueue();
85
+ resolve({ value: stdout, fromCache: false, durationMs: now() - startedAt });
86
+ }
87
+ );
88
+ });
89
+ }
90
+ return {
91
+ exec(command, options2) {
92
+ if (disposed) return Promise.reject(new Error("OneShotPool: disposed"));
93
+ const cacheKey = options2?.cacheKey ?? JSON.stringify({ command, cwd: options2?.cwd ?? null });
94
+ const cached = readCache(cacheKey);
95
+ if (cached !== null) {
96
+ return Promise.resolve({ value: cached.value, fromCache: true, durationMs: 0 });
97
+ }
98
+ const flight = inFlight.get(cacheKey);
99
+ if (flight !== void 0) {
100
+ return flight;
101
+ }
102
+ const promise = activeCount < maxConcurrent ? runExec(command, options2, cacheKey) : new Promise((resolve, reject) => {
103
+ queue.push({
104
+ cacheKey,
105
+ reject,
106
+ run: () => {
107
+ const fresh = readCache(cacheKey);
108
+ if (fresh !== null) {
109
+ resolve({ value: fresh.value, fromCache: true, durationMs: 0 });
110
+ pumpQueue();
111
+ return;
112
+ }
113
+ runExec(command, options2, cacheKey).then(resolve, reject);
114
+ }
115
+ });
116
+ });
117
+ inFlight.set(cacheKey, promise);
118
+ return promise;
119
+ },
120
+ invalidate(cacheKey) {
121
+ if (cacheKey === void 0) {
122
+ cache.clear();
123
+ return;
124
+ }
125
+ cache.delete(cacheKey);
126
+ },
127
+ dispose() {
128
+ disposed = true;
129
+ const pendingRejects = queue.map((item) => item.reject);
130
+ queue.length = 0;
131
+ cache.clear();
132
+ for (const rejectFn of pendingRejects) {
133
+ rejectFn(new Error("OneShotPool: disposed"));
134
+ }
135
+ }
136
+ };
137
+ }
138
+
139
+ // ../../packages/local-runtime/src/json-line-codec.ts
140
+ function createJsonLineCodec(schema) {
141
+ return {
142
+ encode(message) {
143
+ return JSON.stringify(message);
144
+ },
145
+ decode(line) {
146
+ if (line.length === 0) {
147
+ return { ok: false, reason: "empty", error: "Line is empty" };
148
+ }
149
+ let parsed;
150
+ try {
151
+ parsed = JSON.parse(line);
152
+ } catch (err) {
153
+ return {
154
+ ok: false,
155
+ reason: "invalid-json",
156
+ error: err instanceof Error ? err.message : String(err)
157
+ };
158
+ }
159
+ const result = schema.safeParse(parsed);
160
+ if (!result.success) {
161
+ return {
162
+ ok: false,
163
+ reason: "schema",
164
+ error: result.error.message
165
+ };
166
+ }
167
+ return { ok: true, message: result.data };
168
+ }
169
+ };
170
+ }
171
+
172
+ // ../../packages/local-runtime/src/line-dispatcher.ts
173
+ var DEFAULT_MAX_LINES_PER_TICK = 128;
174
+ var DEFAULT_MAX_BUFFERED_BYTES = 8 * 1024 * 1024;
175
+ function createLineDispatcher(options) {
176
+ return new DefaultLineDispatcher(options);
177
+ }
178
+ var DefaultLineDispatcher = class {
179
+ #onLine;
180
+ #onOverflow;
181
+ #maxLinesPerTick;
182
+ #maxBufferedBytes;
183
+ #emitEmptyLines;
184
+ #schedule;
185
+ #buffer = "";
186
+ #scheduled = false;
187
+ constructor(options) {
188
+ this.#onLine = options.onLine;
189
+ this.#onOverflow = options.onOverflow;
190
+ this.#maxLinesPerTick = Math.max(1, options.maxLinesPerTick ?? DEFAULT_MAX_LINES_PER_TICK);
191
+ this.#maxBufferedBytes = Math.max(1, options.maxBufferedBytes ?? DEFAULT_MAX_BUFFERED_BYTES);
192
+ this.#emitEmptyLines = options.emitEmptyLines ?? false;
193
+ this.#schedule = options.schedule ?? ((callback) => setImmediate(callback));
194
+ }
195
+ get bufferedLength() {
196
+ return this.#buffer.length;
197
+ }
198
+ push(chunk) {
199
+ this.#buffer += typeof chunk === "string" ? chunk : chunk.toString("utf8");
200
+ this.flush();
201
+ }
202
+ flush() {
203
+ this.#scheduled = false;
204
+ let processed = 0;
205
+ while (processed < this.#maxLinesPerTick) {
206
+ const newlineIndex = this.#buffer.indexOf("\n");
207
+ if (newlineIndex === -1) {
208
+ this.#enforceBufferedBytes();
209
+ return;
210
+ }
211
+ const line = this.#buffer.slice(0, newlineIndex);
212
+ this.#buffer = this.#buffer.slice(newlineIndex + 1);
213
+ processed += 1;
214
+ if (line.length > 0 || this.#emitEmptyLines) this.#onLine(line);
215
+ }
216
+ if (this.#buffer.includes("\n")) {
217
+ this.#scheduleFlush();
218
+ return;
219
+ }
220
+ this.#enforceBufferedBytes();
221
+ }
222
+ #scheduleFlush() {
223
+ if (this.#scheduled) return;
224
+ this.#scheduled = true;
225
+ this.#schedule(() => this.flush());
226
+ }
227
+ #enforceBufferedBytes() {
228
+ const bytes = Buffer.byteLength(this.#buffer, "utf8");
229
+ if (bytes <= this.#maxBufferedBytes) return;
230
+ this.#buffer = "";
231
+ this.#scheduled = false;
232
+ this.#onOverflow?.({ bytes, maxBytes: this.#maxBufferedBytes });
233
+ }
234
+ };
235
+
236
+ // ../../packages/local-runtime/src/stdio-child-peer.ts
237
+ function createStdioChildPeer(options) {
238
+ const peer = new DefaultStdioChildPeer(options);
239
+ peer.attach();
240
+ return peer;
241
+ }
242
+ var DefaultStdioChildPeer = class {
243
+ process;
244
+ generation;
245
+ #exited = false;
246
+ #stdinFailed = false;
247
+ #inboundCodec;
248
+ #outboundCodec;
249
+ #onMessage;
250
+ #onDecodeFailed;
251
+ #onStderrLine;
252
+ #onExit;
253
+ #onError;
254
+ #onMissingStdout;
255
+ #onOverflow;
256
+ #maxLinesPerTick;
257
+ #maxStdoutBufferedBytes;
258
+ #maxStderrBufferedBytes;
259
+ #scheduleLineFlush;
260
+ constructor(options) {
261
+ this.process = options.process;
262
+ this.generation = options.generation;
263
+ this.#inboundCodec = options.inboundCodec;
264
+ this.#outboundCodec = options.outboundCodec;
265
+ this.#onMessage = options.onMessage;
266
+ this.#onDecodeFailed = options.onDecodeFailed;
267
+ this.#onStderrLine = options.onStderrLine;
268
+ this.#onExit = options.onExit;
269
+ this.#onError = options.onError;
270
+ this.#onMissingStdout = options.onMissingStdout;
271
+ this.#onOverflow = options.onOverflow;
272
+ this.#maxLinesPerTick = options.maxLinesPerTick;
273
+ this.#maxStdoutBufferedBytes = options.maxStdoutBufferedBytes;
274
+ this.#maxStderrBufferedBytes = options.maxStderrBufferedBytes;
275
+ this.#scheduleLineFlush = options.scheduleLineFlush;
276
+ }
277
+ get exited() {
278
+ return this.#exited;
279
+ }
280
+ attach() {
281
+ this.#attachStdin();
282
+ this.#attachStdout();
283
+ this.#attachStderr();
284
+ this.process.on("exit", (code, signal) => {
285
+ this.#exited = true;
286
+ this.#invoke(() => this.#onExit?.({ code, signal, generation: this.generation }));
287
+ });
288
+ this.process.on("error", (err) => {
289
+ this.#reportError(err);
290
+ });
291
+ }
292
+ send(message) {
293
+ const stdin = this.process.stdin;
294
+ if (!stdin || stdin.destroyed || this.#exited || this.#stdinFailed) return false;
295
+ try {
296
+ stdin.write(`${this.#outboundCodec.encode(message)}
297
+ `, (err) => {
298
+ if (err) this.#handleStdinError(err);
299
+ });
300
+ return true;
301
+ } catch (err) {
302
+ this.#handleStdinError(toError(err));
303
+ return false;
304
+ }
305
+ }
306
+ #attachStdin() {
307
+ const stdin = this.process.stdin;
308
+ if (!stdin) return;
309
+ stdin.on("error", (err) => {
310
+ this.#handleStdinError(err);
311
+ });
312
+ }
313
+ #attachStdout() {
314
+ const stdout = this.process.stdout;
315
+ if (!stdout) {
316
+ this.#invoke(() => this.#onMissingStdout?.(this.generation));
317
+ return;
318
+ }
319
+ stdout.setEncoding("utf8");
320
+ const dispatcher = this.#createDispatcher("stdout", (line) => {
321
+ const decoded = this.#inboundCodec.decode(line);
322
+ this.#handleDecodedLine(line, decoded);
323
+ });
324
+ stdout.on("data", (chunk) => {
325
+ dispatcher.push(chunk);
326
+ });
327
+ }
328
+ #attachStderr() {
329
+ const stderr = this.process.stderr;
330
+ if (!stderr || !this.#onStderrLine && !this.#onOverflow) return;
331
+ stderr.setEncoding("utf8");
332
+ const dispatcher = this.#createDispatcher("stderr", (line) => {
333
+ this.#invoke(() => this.#onStderrLine?.(line, this.generation));
334
+ });
335
+ stderr.on("data", (chunk) => {
336
+ dispatcher.push(chunk);
337
+ });
338
+ }
339
+ #createDispatcher(stream, onLine) {
340
+ return createLineDispatcher({
341
+ onLine,
342
+ onOverflow: (overflow) => this.#handleOverflow(stream, overflow),
343
+ maxLinesPerTick: this.#maxLinesPerTick,
344
+ maxBufferedBytes: stream === "stdout" ? this.#maxStdoutBufferedBytes : this.#maxStderrBufferedBytes,
345
+ schedule: this.#scheduleLineFlush
346
+ });
347
+ }
348
+ #handleOverflow(stream, overflow) {
349
+ this.#invoke(
350
+ () => this.#onOverflow?.({
351
+ stream,
352
+ bytes: overflow.bytes,
353
+ maxBytes: overflow.maxBytes,
354
+ generation: this.generation
355
+ })
356
+ );
357
+ }
358
+ #handleDecodedLine(line, decoded) {
359
+ if (decoded.ok) {
360
+ this.#invoke(() => this.#onMessage(decoded.message, this.generation));
361
+ return;
362
+ }
363
+ if (decoded.reason === "empty") return;
364
+ this.#invoke(
365
+ () => this.#onDecodeFailed?.({
366
+ line,
367
+ reason: decoded.reason,
368
+ error: decoded.error,
369
+ generation: this.generation
370
+ })
371
+ );
372
+ }
373
+ #handleStdinError(err) {
374
+ const wasFailed = this.#stdinFailed;
375
+ this.#stdinFailed = true;
376
+ if (!wasFailed) this.#reportError(err);
377
+ }
378
+ #invoke(fn) {
379
+ try {
380
+ fn();
381
+ } catch (err) {
382
+ this.#reportError(toError(err));
383
+ }
384
+ }
385
+ #reportError(err) {
386
+ try {
387
+ this.#onError?.(err, this.generation);
388
+ } catch {
389
+ }
390
+ }
391
+ };
392
+ function toError(err) {
393
+ return err instanceof Error ? err : new Error(String(err));
394
+ }
395
+
396
+ // ../../packages/local-runtime/src/service-supervisor.ts
397
+ var DEFAULT_MAX_DEATHS_PER_WINDOW = 5;
398
+ var DEFAULT_DEATH_WINDOW_MS = 6e4;
399
+ var DEFAULT_COOLDOWN_MS = 3e5;
400
+ function createServiceSupervisor(deps) {
401
+ let live = null;
402
+ let nextGeneration = 1;
403
+ let disposed = false;
404
+ const circuit = { deaths: [], openedAt: null };
405
+ const circuitMaxDeaths = deps.circuit?.maxDeathsPerWindow ?? DEFAULT_MAX_DEATHS_PER_WINDOW;
406
+ const circuitWindowMs = deps.circuit?.deathWindowMs ?? DEFAULT_DEATH_WINDOW_MS;
407
+ const circuitCooldownMs = deps.circuit?.cooldownMs ?? DEFAULT_COOLDOWN_MS;
408
+ const circuitEnabled = deps.circuit !== void 0;
409
+ function isCircuitOpen() {
410
+ if (!circuitEnabled) return false;
411
+ if (circuit.openedAt === null) return false;
412
+ const elapsed = deps.now() - circuit.openedAt;
413
+ if (elapsed >= circuitCooldownMs) {
414
+ circuit.openedAt = null;
415
+ circuit.deaths.length = 0;
416
+ deps.log({ event: "service_supervisor_circuit_closed" });
417
+ return false;
418
+ }
419
+ return true;
420
+ }
421
+ function recordDeath() {
422
+ if (!circuitEnabled) return;
423
+ const now = deps.now();
424
+ const cutoff = now - circuitWindowMs;
425
+ while (circuit.deaths.length > 0) {
426
+ const head = circuit.deaths[0];
427
+ if (head !== void 0 && head < cutoff) {
428
+ circuit.deaths.shift();
429
+ continue;
430
+ }
431
+ break;
432
+ }
433
+ circuit.deaths.push(now);
434
+ if (circuit.deaths.length >= circuitMaxDeaths && circuit.openedAt === null) {
435
+ circuit.openedAt = now;
436
+ deps.log({
437
+ event: "service_supervisor_circuit_opened",
438
+ deathCount: circuit.deaths.length,
439
+ cooldownMs: circuitCooldownMs
440
+ });
441
+ }
442
+ }
443
+ function spawn() {
444
+ const generation = nextGeneration++;
445
+ const proc = deps.fork(deps.workerPath, deps.workerArgs ?? [], {
446
+ stdio: ["pipe", "pipe", "pipe", "ipc"]
447
+ });
448
+ const peer = createStdioChildPeer({
449
+ process: proc,
450
+ generation,
451
+ inboundCodec: deps.replyCodec,
452
+ outboundCodec: deps.commandCodec,
453
+ onMessage: (reply, fromGeneration) => {
454
+ deps.onReply(reply, fromGeneration);
455
+ },
456
+ onDecodeFailed: deps.onDecodeFailed,
457
+ onStderrLine: deps.onStderrLine,
458
+ onMissingStdout: deps.onMissingStdout,
459
+ onOverflow: deps.onOverflow,
460
+ onError: deps.onPeerError,
461
+ onExit: ({ code, signal, generation: exitGeneration }) => {
462
+ handleExit(exitGeneration, code, signal);
463
+ }
464
+ });
465
+ const holder = {
466
+ process: proc,
467
+ peer,
468
+ generation,
469
+ spawnedAt: deps.now(),
470
+ exited: false
471
+ };
472
+ deps.log({ event: "service_supervisor_started", pid: proc.pid ?? null, generation });
473
+ deps.onChildSpawned?.({ generation, pid: proc.pid ?? null });
474
+ return holder;
475
+ }
476
+ function handleExit(exitGeneration, code, signal) {
477
+ if (live === null || exitGeneration !== live.generation) return;
478
+ const finished = live;
479
+ finished.exited = true;
480
+ live = null;
481
+ const uptimeMs = deps.now() - finished.spawnedAt;
482
+ recordDeath();
483
+ deps.onChildExit({ code, signal, generation: exitGeneration, uptimeMs });
484
+ }
485
+ function killCurrentIfAlive() {
486
+ if (live === null) return;
487
+ const dying = live;
488
+ live = null;
489
+ if (dying.exited) return;
490
+ try {
491
+ dying.process.kill("SIGKILL");
492
+ } catch (err) {
493
+ deps.log({
494
+ event: "service_supervisor_kill_failed",
495
+ err: err instanceof Error ? err.message : String(err)
496
+ });
497
+ }
498
+ }
499
+ return {
500
+ get generation() {
501
+ return live?.generation ?? 0;
502
+ },
503
+ get healthy() {
504
+ return live !== null && !isCircuitOpen();
505
+ },
506
+ get circuitOpen() {
507
+ return isCircuitOpen();
508
+ },
509
+ start() {
510
+ if (disposed) return;
511
+ if (live !== null) return;
512
+ live = spawn();
513
+ },
514
+ send(command) {
515
+ if (live === null) return false;
516
+ return live.peer.send(command);
517
+ },
518
+ restart() {
519
+ if (disposed) return false;
520
+ if (isCircuitOpen()) {
521
+ deps.log({ event: "service_supervisor_restart_blocked_circuit_open" });
522
+ return false;
523
+ }
524
+ killCurrentIfAlive();
525
+ live = spawn();
526
+ return true;
527
+ },
528
+ dispose() {
529
+ disposed = true;
530
+ },
531
+ getCurrentProcess() {
532
+ return live?.process ?? null;
533
+ }
534
+ };
535
+ }
536
+
537
+ export {
538
+ createJsonLineCodec,
539
+ createOneShotPool,
540
+ createServiceSupervisor
541
+ };
542
+ //# sourceMappingURL=chunk-ZFKJAYAN.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../packages/local-runtime/src/one-shot-pool.ts","../../../packages/local-runtime/src/json-line-codec.ts","../../../packages/local-runtime/src/line-dispatcher.ts","../../../packages/local-runtime/src/stdio-child-peer.ts","../../../packages/local-runtime/src/service-supervisor.ts"],"sourcesContent":["import { execFile } from 'node:child_process';\n\n/**\n * Subprocess-per-call dispatcher with two superpowers:\n *\n * 1. **TTL cache** — successful results are memoized for `ttlMs`. A second\n * call with the same cache key inside the window returns the cached\n * value without spawning. Failures are NOT cached (errors should be\n * re-attempted).\n *\n * 2. **In-flight coalescing** — if a call with cache key K is in-flight\n * when a second call with key K arrives, the second caller awaits the\n * same promise. Net result: at most one subprocess for K at a time,\n * regardless of N concurrent callers.\n *\n * This primitive is the substrate for routing `lsof`, `gh`, and `git`\n * one-shot CLI invocations off the daemon's main event loop. It uses\n * `child_process.execFile` (not `spawn`) — short-lived, captured-output,\n * no streaming. For long-lived workers use ServiceSupervisor instead.\n */\n\nexport interface OneShotPoolOptions {\n /**\n * How long a successful result stays cached. Set to 0 to disable\n * caching while keeping coalescing.\n */\n readonly ttlMs: number;\n /**\n * Maximum number of subprocesses in flight at once across all keys.\n * Defaults to 1 (serialized) — appropriate for tools that hammer the\n * same resource (lsof, gh) where parallelism produces no speedup.\n * Excess calls queue FIFO.\n */\n readonly maxConcurrent?: number;\n}\n\nexport interface OneShotExecOptions {\n /**\n * Stable key for cache + coalescing. Defaults to JSON.stringify(command).\n * Override when arguments include variable detail you want to ignore\n * (e.g. a `--timestamp` flag the caller never inspects).\n */\n readonly cacheKey?: string;\n readonly env?: Record<string, string>;\n /**\n * Hard timeout for the child process in ms. If exceeded, the child is\n * killed and exec rejects.\n */\n readonly timeoutMs?: number;\n /**\n * Maximum stdout/stderr buffer size in bytes. Overflow rejects exec.\n * Defaults to 10MB.\n */\n readonly maxBufferBytes?: number;\n /**\n * Working directory for the child process. Defaults to the daemon cwd.\n */\n readonly cwd?: string;\n}\n\nexport interface OneShotPoolResult {\n readonly value: string;\n readonly fromCache: boolean;\n readonly durationMs: number;\n}\n\nexport interface OneShotPool {\n /**\n * Execute a command. First arg of `command` is the executable; rest are\n * its arguments. Returns the captured stdout. Stderr is included in\n * thrown errors but not returned on success.\n */\n exec(command: readonly string[], options?: OneShotExecOptions): Promise<OneShotPoolResult>;\n /** Invalidate a specific cache key, or all entries if omitted. */\n invalidate(cacheKey?: string): void;\n /** Stop accepting new exec calls and abandon queued ones. */\n dispose(): void;\n}\n\n/**\n * Injectable execFile-like function. Overridable for tests so we don't\n * shell out to real binaries.\n */\nexport interface ExecFileError extends Error {\n /** Process exit code or null if killed by a signal. */\n readonly code?: number | string | null;\n /** Signal that killed the process, or null. */\n readonly signal?: NodeJS.Signals | null;\n}\n\nexport type ExecFileLike = (\n file: string,\n args: readonly string[],\n options: {\n env?: Record<string, string>;\n timeout?: number;\n maxBuffer?: number;\n cwd?: string;\n },\n callback: (err: ExecFileError | null, stdout: string, stderr: string) => void\n) => void;\n\n/**\n * Adapts node:child_process.execFile to the narrower ExecFileLike contract.\n * Lives at module scope to avoid recreating the closure on every pool.\n */\nconst defaultExecFile: ExecFileLike = (file, args, opts, cb) => {\n execFile(\n file,\n [...args],\n {\n env: opts.env,\n timeout: opts.timeout,\n maxBuffer: opts.maxBuffer,\n cwd: opts.cwd,\n encoding: 'utf8',\n },\n (err, stdout, stderr) => {\n cb(err, stdout, stderr);\n }\n );\n};\n\nexport interface OneShotPoolDeps {\n /** Inject for tests; defaults to node:child_process.execFile. */\n readonly execFile?: ExecFileLike;\n readonly now?: () => number;\n}\n\ninterface CacheEntry {\n readonly value: string;\n readonly expiresAt: number;\n}\n\ninterface QueuedCall {\n readonly cacheKey: string;\n readonly run: () => void;\n readonly reject: (err: Error) => void;\n}\n\nconst DEFAULT_MAX_CONCURRENT = 1;\nconst DEFAULT_MAX_BUFFER_BYTES = 10 * 1024 * 1024;\n\nexport function createOneShotPool(\n options: OneShotPoolOptions,\n deps: OneShotPoolDeps = {}\n): OneShotPool {\n const ttlMs = options.ttlMs;\n const maxConcurrent = options.maxConcurrent ?? DEFAULT_MAX_CONCURRENT;\n const execFileImpl: ExecFileLike = deps.execFile ?? defaultExecFile;\n const now: () => number = deps.now ?? (() => Date.now());\n\n const cache = new Map<string, CacheEntry>();\n const inFlight = new Map<string, Promise<OneShotPoolResult>>();\n const queue: QueuedCall[] = [];\n let activeCount = 0;\n let disposed = false;\n\n function readCache(key: string): CacheEntry | null {\n const entry = cache.get(key);\n if (entry === undefined) return null;\n if (entry.expiresAt <= now()) {\n cache.delete(key);\n return null;\n }\n return entry;\n }\n\n function writeCache(key: string, value: string): void {\n if (ttlMs <= 0) return;\n cache.set(key, { value, expiresAt: now() + ttlMs });\n }\n\n function pumpQueue(): void {\n while (queue.length > 0 && activeCount < maxConcurrent) {\n const next = queue.shift();\n if (next === undefined) return;\n next.run();\n }\n }\n\n function runExec(\n command: readonly string[],\n options: OneShotExecOptions | undefined,\n cacheKey: string\n ): Promise<OneShotPoolResult> {\n activeCount += 1;\n const startedAt = now();\n const [file, ...args] = command;\n if (file === undefined) {\n activeCount -= 1;\n pumpQueue();\n return Promise.reject(new Error('OneShotPool.exec: empty command array'));\n }\n return new Promise<OneShotPoolResult>((resolve, reject) => {\n execFileImpl(\n file,\n args,\n {\n env: options?.env,\n timeout: options?.timeoutMs,\n maxBuffer: options?.maxBufferBytes ?? DEFAULT_MAX_BUFFER_BYTES,\n cwd: options?.cwd,\n },\n (err, stdout, stderr) => {\n activeCount -= 1;\n if (err !== null) {\n const message = stderr.length > 0 ? `${err.message}: ${stderr}` : err.message;\n const wrapped = new Error(message, { cause: err });\n inFlight.delete(cacheKey);\n pumpQueue();\n reject(wrapped);\n return;\n }\n writeCache(cacheKey, stdout);\n inFlight.delete(cacheKey);\n pumpQueue();\n resolve({ value: stdout, fromCache: false, durationMs: now() - startedAt });\n }\n );\n });\n }\n\n return {\n exec(command, options) {\n if (disposed) return Promise.reject(new Error('OneShotPool: disposed'));\n /** cwd included so same args in different repos never share a cache entry. */\n const cacheKey = options?.cacheKey ?? JSON.stringify({ command, cwd: options?.cwd ?? null });\n\n const cached = readCache(cacheKey);\n if (cached !== null) {\n return Promise.resolve({ value: cached.value, fromCache: true, durationMs: 0 });\n }\n\n const flight = inFlight.get(cacheKey);\n if (flight !== undefined) {\n /**\n * Coalesce: return the same promise. fromCache is reported as\n * false because the underlying call hasn't completed; durationMs\n * will reflect the leader's total time, not the follower's wait.\n */\n return flight;\n }\n\n const promise: Promise<OneShotPoolResult> =\n activeCount < maxConcurrent\n ? runExec(command, options, cacheKey)\n : new Promise<OneShotPoolResult>((resolve, reject) => {\n queue.push({\n cacheKey,\n reject,\n run: () => {\n /**\n * When the queued call dequeues, the cache may have been\n * populated by an earlier sibling call (different cacheKey\n * but same logical query). Re-check cache to avoid wasted\n * subprocesses.\n */\n const fresh = readCache(cacheKey);\n if (fresh !== null) {\n resolve({ value: fresh.value, fromCache: true, durationMs: 0 });\n pumpQueue();\n return;\n }\n runExec(command, options, cacheKey).then(resolve, reject);\n },\n });\n });\n\n inFlight.set(cacheKey, promise);\n return promise;\n },\n invalidate(cacheKey) {\n if (cacheKey === undefined) {\n cache.clear();\n return;\n }\n cache.delete(cacheKey);\n },\n dispose() {\n disposed = true;\n const pendingRejects = queue.map((item) => item.reject);\n queue.length = 0;\n cache.clear();\n for (const rejectFn of pendingRejects) {\n rejectFn(new Error('OneShotPool: disposed'));\n }\n },\n };\n}\n","import type { z } from 'zod';\n\nexport type JsonLineDecodeFailureReason = 'empty' | 'invalid-json' | 'schema';\n\nexport type JsonLineDecodeResult<TMessage> =\n | { ok: true; message: TMessage }\n | {\n ok: false;\n reason: JsonLineDecodeFailureReason;\n error: string;\n };\n\nexport interface JsonLineCodec<TMessage> {\n encode(message: TMessage): string;\n decode(line: string): JsonLineDecodeResult<TMessage>;\n}\n\nexport function createJsonLineCodec<TMessage>(\n schema: z.ZodType<TMessage>\n): JsonLineCodec<TMessage> {\n return {\n encode(message) {\n return JSON.stringify(message);\n },\n decode(line) {\n if (line.length === 0) {\n return { ok: false, reason: 'empty', error: 'Line is empty' };\n }\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(line);\n } catch (err) {\n return {\n ok: false,\n reason: 'invalid-json',\n error: err instanceof Error ? err.message : String(err),\n };\n }\n\n const result = schema.safeParse(parsed);\n if (!result.success) {\n return {\n ok: false,\n reason: 'schema',\n error: result.error.message,\n };\n }\n return { ok: true, message: result.data };\n },\n };\n}\n","export interface LineDispatchOverflow {\n readonly bytes: number;\n readonly maxBytes: number;\n}\n\nexport interface LineDispatcher {\n readonly bufferedLength: number;\n push(chunk: Buffer | string): void;\n flush(): void;\n}\n\nexport interface LineDispatcherOptions {\n readonly onLine: (line: string) => void;\n readonly onOverflow?: (overflow: LineDispatchOverflow) => void;\n readonly maxLinesPerTick?: number;\n readonly maxBufferedBytes?: number;\n readonly emitEmptyLines?: boolean;\n readonly schedule?: (callback: () => void) => void;\n}\n\nconst DEFAULT_MAX_LINES_PER_TICK = 128;\nconst DEFAULT_MAX_BUFFERED_BYTES = 8 * 1024 * 1024;\n\nexport function createLineDispatcher(options: LineDispatcherOptions): LineDispatcher {\n return new DefaultLineDispatcher(options);\n}\n\nclass DefaultLineDispatcher implements LineDispatcher {\n readonly #onLine: (line: string) => void;\n readonly #onOverflow?: (overflow: LineDispatchOverflow) => void;\n readonly #maxLinesPerTick: number;\n readonly #maxBufferedBytes: number;\n readonly #emitEmptyLines: boolean;\n readonly #schedule: (callback: () => void) => void;\n #buffer = '';\n #scheduled = false;\n\n constructor(options: LineDispatcherOptions) {\n this.#onLine = options.onLine;\n this.#onOverflow = options.onOverflow;\n this.#maxLinesPerTick = Math.max(1, options.maxLinesPerTick ?? DEFAULT_MAX_LINES_PER_TICK);\n this.#maxBufferedBytes = Math.max(1, options.maxBufferedBytes ?? DEFAULT_MAX_BUFFERED_BYTES);\n this.#emitEmptyLines = options.emitEmptyLines ?? false;\n this.#schedule = options.schedule ?? ((callback) => setImmediate(callback));\n }\n\n get bufferedLength(): number {\n return this.#buffer.length;\n }\n\n push(chunk: Buffer | string): void {\n this.#buffer += typeof chunk === 'string' ? chunk : chunk.toString('utf8');\n this.flush();\n }\n\n flush(): void {\n this.#scheduled = false;\n let processed = 0;\n while (processed < this.#maxLinesPerTick) {\n const newlineIndex = this.#buffer.indexOf('\\n');\n if (newlineIndex === -1) {\n this.#enforceBufferedBytes();\n return;\n }\n const line = this.#buffer.slice(0, newlineIndex);\n this.#buffer = this.#buffer.slice(newlineIndex + 1);\n processed += 1;\n if (line.length > 0 || this.#emitEmptyLines) this.#onLine(line);\n }\n if (this.#buffer.includes('\\n')) {\n this.#scheduleFlush();\n return;\n }\n this.#enforceBufferedBytes();\n }\n\n #scheduleFlush(): void {\n if (this.#scheduled) return;\n this.#scheduled = true;\n this.#schedule(() => this.flush());\n }\n\n #enforceBufferedBytes(): void {\n const bytes = Buffer.byteLength(this.#buffer, 'utf8');\n if (bytes <= this.#maxBufferedBytes) return;\n this.#buffer = '';\n this.#scheduled = false;\n this.#onOverflow?.({ bytes, maxBytes: this.#maxBufferedBytes });\n }\n}\n","import type { EventEmitter } from 'node:events';\nimport type { Readable, Writable } from 'node:stream';\nimport type {\n JsonLineCodec,\n JsonLineDecodeFailureReason,\n JsonLineDecodeResult,\n} from './json-line-codec';\nimport {\n createLineDispatcher,\n type LineDispatcher,\n type LineDispatchOverflow,\n} from './line-dispatcher';\n\nexport interface StdioChildProcessLike extends EventEmitter {\n readonly stdin: Writable | null;\n readonly stdout: Readable | null;\n readonly stderr: Readable | null;\n readonly pid?: number;\n kill(signal?: NodeJS.Signals | number): boolean;\n}\n\nexport interface StdioChildPeer<TOutbound> {\n readonly process: StdioChildProcessLike;\n readonly generation: number;\n readonly exited: boolean;\n send(message: TOutbound): boolean;\n}\n\nexport interface StdioChildDecodeFailure {\n readonly line: string;\n readonly reason: JsonLineDecodeFailureReason;\n readonly error: string;\n readonly generation: number;\n}\n\nexport interface StdioChildOverflow {\n readonly bytes: number;\n readonly maxBytes: number;\n readonly stream: 'stdout' | 'stderr';\n readonly generation: number;\n}\n\nexport interface StdioChildExitInfo {\n readonly code: number | null;\n readonly signal: NodeJS.Signals | null;\n readonly generation: number;\n}\n\nexport interface StdioChildPeerOptions<TInbound, TOutbound> {\n readonly process: StdioChildProcessLike;\n readonly generation: number;\n readonly inboundCodec: Pick<JsonLineCodec<TInbound>, 'decode'>;\n readonly outboundCodec: Pick<JsonLineCodec<TOutbound>, 'encode'>;\n readonly onMessage: (message: TInbound, generation: number) => void;\n readonly onDecodeFailed?: (failure: StdioChildDecodeFailure) => void;\n readonly onStderrLine?: (line: string, generation: number) => void;\n readonly onExit?: (info: StdioChildExitInfo) => void;\n readonly onError?: (err: Error, generation: number) => void;\n readonly onMissingStdout?: (generation: number) => void;\n readonly onOverflow?: (overflow: StdioChildOverflow) => void;\n readonly maxLinesPerTick?: number;\n readonly maxStdoutBufferedBytes?: number;\n readonly maxStderrBufferedBytes?: number;\n readonly scheduleLineFlush?: (callback: () => void) => void;\n}\n\nexport function createStdioChildPeer<TInbound, TOutbound>(\n options: StdioChildPeerOptions<TInbound, TOutbound>\n): StdioChildPeer<TOutbound> {\n const peer = new DefaultStdioChildPeer(options);\n peer.attach();\n return peer;\n}\n\nclass DefaultStdioChildPeer<TInbound, TOutbound> implements StdioChildPeer<TOutbound> {\n readonly process: StdioChildProcessLike;\n readonly generation: number;\n #exited = false;\n #stdinFailed = false;\n readonly #inboundCodec: Pick<JsonLineCodec<TInbound>, 'decode'>;\n readonly #outboundCodec: Pick<JsonLineCodec<TOutbound>, 'encode'>;\n readonly #onMessage: (message: TInbound, generation: number) => void;\n readonly #onDecodeFailed?: (failure: StdioChildDecodeFailure) => void;\n readonly #onStderrLine?: (line: string, generation: number) => void;\n readonly #onExit?: (info: StdioChildExitInfo) => void;\n readonly #onError?: (err: Error, generation: number) => void;\n readonly #onMissingStdout?: (generation: number) => void;\n readonly #onOverflow?: (overflow: StdioChildOverflow) => void;\n readonly #maxLinesPerTick?: number;\n readonly #maxStdoutBufferedBytes?: number;\n readonly #maxStderrBufferedBytes?: number;\n readonly #scheduleLineFlush?: (callback: () => void) => void;\n\n constructor(options: StdioChildPeerOptions<TInbound, TOutbound>) {\n this.process = options.process;\n this.generation = options.generation;\n this.#inboundCodec = options.inboundCodec;\n this.#outboundCodec = options.outboundCodec;\n this.#onMessage = options.onMessage;\n this.#onDecodeFailed = options.onDecodeFailed;\n this.#onStderrLine = options.onStderrLine;\n this.#onExit = options.onExit;\n this.#onError = options.onError;\n this.#onMissingStdout = options.onMissingStdout;\n this.#onOverflow = options.onOverflow;\n this.#maxLinesPerTick = options.maxLinesPerTick;\n this.#maxStdoutBufferedBytes = options.maxStdoutBufferedBytes;\n this.#maxStderrBufferedBytes = options.maxStderrBufferedBytes;\n this.#scheduleLineFlush = options.scheduleLineFlush;\n }\n\n get exited(): boolean {\n return this.#exited;\n }\n\n attach(): void {\n this.#attachStdin();\n this.#attachStdout();\n this.#attachStderr();\n this.process.on('exit', (code: number | null, signal: NodeJS.Signals | null) => {\n this.#exited = true;\n this.#invoke(() => this.#onExit?.({ code, signal, generation: this.generation }));\n });\n this.process.on('error', (err: Error) => {\n this.#reportError(err);\n });\n }\n\n send(message: TOutbound): boolean {\n const stdin = this.process.stdin;\n if (!stdin || stdin.destroyed || this.#exited || this.#stdinFailed) return false;\n try {\n stdin.write(`${this.#outboundCodec.encode(message)}\\n`, (err?: Error | null) => {\n if (err) this.#handleStdinError(err);\n });\n return true;\n } catch (err) {\n this.#handleStdinError(toError(err));\n return false;\n }\n }\n\n #attachStdin(): void {\n const stdin = this.process.stdin;\n if (!stdin) return;\n stdin.on('error', (err: Error) => {\n this.#handleStdinError(err);\n });\n }\n\n #attachStdout(): void {\n const stdout = this.process.stdout;\n if (!stdout) {\n this.#invoke(() => this.#onMissingStdout?.(this.generation));\n return;\n }\n stdout.setEncoding('utf8');\n const dispatcher = this.#createDispatcher('stdout', (line) => {\n const decoded = this.#inboundCodec.decode(line);\n this.#handleDecodedLine(line, decoded);\n });\n stdout.on('data', (chunk: Buffer | string) => {\n dispatcher.push(chunk);\n });\n }\n\n #attachStderr(): void {\n const stderr = this.process.stderr;\n if (!stderr || (!this.#onStderrLine && !this.#onOverflow)) return;\n stderr.setEncoding('utf8');\n const dispatcher = this.#createDispatcher('stderr', (line) => {\n this.#invoke(() => this.#onStderrLine?.(line, this.generation));\n });\n stderr.on('data', (chunk: Buffer | string) => {\n dispatcher.push(chunk);\n });\n }\n\n #createDispatcher(stream: 'stdout' | 'stderr', onLine: (line: string) => void): LineDispatcher {\n return createLineDispatcher({\n onLine,\n onOverflow: (overflow) => this.#handleOverflow(stream, overflow),\n maxLinesPerTick: this.#maxLinesPerTick,\n maxBufferedBytes:\n stream === 'stdout' ? this.#maxStdoutBufferedBytes : this.#maxStderrBufferedBytes,\n schedule: this.#scheduleLineFlush,\n });\n }\n\n #handleOverflow(stream: 'stdout' | 'stderr', overflow: LineDispatchOverflow): void {\n this.#invoke(() =>\n this.#onOverflow?.({\n stream,\n bytes: overflow.bytes,\n maxBytes: overflow.maxBytes,\n generation: this.generation,\n })\n );\n }\n\n #handleDecodedLine(line: string, decoded: JsonLineDecodeResult<TInbound>): void {\n if (decoded.ok) {\n this.#invoke(() => this.#onMessage(decoded.message, this.generation));\n return;\n }\n if (decoded.reason === 'empty') return;\n this.#invoke(() =>\n this.#onDecodeFailed?.({\n line,\n reason: decoded.reason,\n error: decoded.error,\n generation: this.generation,\n })\n );\n }\n\n #handleStdinError(err: Error): void {\n const wasFailed = this.#stdinFailed;\n this.#stdinFailed = true;\n if (!wasFailed) this.#reportError(err);\n }\n\n #invoke(fn: () => void): void {\n try {\n fn();\n } catch (err) {\n this.#reportError(toError(err));\n }\n }\n\n #reportError(err: Error): void {\n try {\n this.#onError?.(err, this.generation);\n } catch {}\n }\n}\n\nfunction toError(err: unknown): Error {\n return err instanceof Error ? err : new Error(String(err));\n}\n","import type { JsonLineCodec } from './json-line-codec';\nimport {\n createStdioChildPeer,\n type StdioChildOverflow,\n type StdioChildPeer,\n type StdioChildProcessLike,\n} from './stdio-child-peer';\n\n/**\n * Generic subprocess supervision primitive. Owns: process lifecycle, peer\n * attachment, generation tokens (so stale post-respawn replies can be\n * dropped), and a simple deaths-per-window restart circuit.\n *\n * What this primitive intentionally does NOT own:\n * - replay-on-respawn semantics (consumer concern — what to re-send when a\n * new child comes up)\n * - half-open / decaying-cooldown circuit logic (consumers like the file\n * watcher have their own subscription-ack-tied circuit and can opt out of\n * the built-in one)\n * - shutdown signal escalation (SIGTERM → SIGKILL with deadlines) — left to\n * consumers since the desired grace period varies wildly per service\n */\n\nexport type ServiceSupervisorLogger = (entry: { event: string; [key: string]: unknown }) => void;\n\nexport type ForkLike = (\n modulePath: string,\n args: readonly string[],\n options: { stdio: ['pipe', 'pipe', 'pipe', 'ipc'] }\n) => StdioChildProcessLike;\n\nexport interface ServiceSupervisorDeps<TCommand, TReply> {\n /** Fork factory. Returns a stdio-bearing child process. */\n readonly fork: ForkLike;\n /** Path to the worker module. */\n readonly workerPath: string;\n /** Arguments passed to fork. Empty by default. */\n readonly workerArgs?: readonly string[];\n /** Codec for commands sent parent -> child. */\n readonly commandCodec: Pick<JsonLineCodec<TCommand>, 'encode'>;\n /** Codec for replies received child -> parent. */\n readonly replyCodec: Pick<JsonLineCodec<TReply>, 'decode'>;\n /**\n * Invoked for each well-formed reply. `generation` identifies which child\n * produced it — consumers should compare against `supervisor.generation`\n * and drop stale replies.\n */\n readonly onReply: (reply: TReply, generation: number) => void;\n /**\n * Invoked when a child exits. Consumer decides whether to replay state\n * and whether to call `restart()` (for example, after a synthetic\n * eviction event has been delivered).\n */\n readonly onChildExit: (info: {\n code: number | null;\n signal: NodeJS.Signals | null;\n generation: number;\n uptimeMs: number;\n }) => void;\n /**\n * Optional. Invoked after a successful fork and peer attach. Consumers\n * use this to replay subscriptions or send an initial command burst.\n */\n readonly onChildSpawned?: (info: { generation: number; pid: number | null }) => void;\n /** Optional malformed-line reporter (passed through from StdioChildPeer). */\n readonly onDecodeFailed?: (failure: {\n line: string;\n reason: string;\n error: string;\n generation: number;\n }) => void;\n /** Optional stderr line forwarder. */\n readonly onStderrLine?: (line: string, generation: number) => void;\n /** Optional stdout-missing reporter. */\n readonly onMissingStdout?: (generation: number) => void;\n /** Optional stdio overflow reporter. */\n readonly onOverflow?: (overflow: StdioChildOverflow) => void;\n /** Optional peer-level error reporter. */\n readonly onPeerError?: (err: Error, generation: number) => void;\n\n readonly log: ServiceSupervisorLogger;\n readonly now: () => number;\n\n /**\n * Built-in restart circuit configuration. When omitted the circuit is\n * disabled — `restart()` always proceeds and consumers manage their own\n * backoff. Provided primarily so simple consumers don't have to reinvent\n * the deaths-per-window pattern.\n */\n readonly circuit?: CircuitConfig;\n}\n\nexport interface CircuitConfig {\n /** Default 5. */\n readonly maxDeathsPerWindow?: number;\n /** Default 60_000ms. */\n readonly deathWindowMs?: number;\n /** Default 300_000ms (5 minutes). */\n readonly cooldownMs?: number;\n}\n\nexport interface ServiceSupervisor<TCommand> {\n /**\n * Generation of the currently live child (0 before first spawn). Each\n * fork bumps this. Consumers can capture this value when registering\n * subscriptions/correlation IDs and compare on reply.\n */\n readonly generation: number;\n /**\n * True iff the built-in circuit is closed (or absent) AND a child has\n * been spawned at least once. Health does NOT reflect whether the live\n * child has acked anything — that's a domain concern.\n */\n readonly healthy: boolean;\n /** Whether the circuit is currently open (cooling down). */\n readonly circuitOpen: boolean;\n /** Fork the first child. No-op if a child is already live. */\n start(): void;\n /**\n * Send a command to the live child. Returns false if no child is live or\n * the stdio pipe is dead.\n */\n send(command: TCommand): boolean;\n /**\n * Request a respawn. The supervisor checks the built-in circuit (if\n * configured); if the circuit is open, returns false. Otherwise kills\n * the current child (if any) and forks a fresh one. Consumers typically\n * call this from `onChildExit`.\n */\n restart(): boolean;\n /**\n * Stop the supervisor. Marks shutdown so no further respawns happen.\n * Does NOT kill the current child — consumers handle their own\n * graceful-shutdown escalation against `getCurrentProcess()`.\n */\n dispose(): void;\n /**\n * Returns the live child process, or null. Exposed so consumers can\n * implement their own kill escalation without going through the\n * supervisor's lifecycle.\n */\n getCurrentProcess(): StdioChildProcessLike | null;\n}\n\ninterface LiveChild<TCommand> {\n readonly process: StdioChildProcessLike;\n readonly peer: StdioChildPeer<TCommand>;\n readonly generation: number;\n readonly spawnedAt: number;\n exited: boolean;\n}\n\ninterface CircuitState {\n /** Death timestamps within the rolling window. */\n readonly deaths: number[];\n /** When the cooldown opened, or null if closed. */\n openedAt: number | null;\n}\n\nconst DEFAULT_MAX_DEATHS_PER_WINDOW = 5;\nconst DEFAULT_DEATH_WINDOW_MS = 60_000;\nconst DEFAULT_COOLDOWN_MS = 300_000;\n\nexport function createServiceSupervisor<TCommand, TReply>(\n deps: ServiceSupervisorDeps<TCommand, TReply>\n): ServiceSupervisor<TCommand> {\n let live: LiveChild<TCommand> | null = null;\n let nextGeneration = 1;\n let disposed = false;\n const circuit: CircuitState = { deaths: [], openedAt: null };\n\n const circuitMaxDeaths = deps.circuit?.maxDeathsPerWindow ?? DEFAULT_MAX_DEATHS_PER_WINDOW;\n const circuitWindowMs = deps.circuit?.deathWindowMs ?? DEFAULT_DEATH_WINDOW_MS;\n const circuitCooldownMs = deps.circuit?.cooldownMs ?? DEFAULT_COOLDOWN_MS;\n const circuitEnabled = deps.circuit !== undefined;\n\n function isCircuitOpen(): boolean {\n if (!circuitEnabled) return false;\n if (circuit.openedAt === null) return false;\n const elapsed = deps.now() - circuit.openedAt;\n if (elapsed >= circuitCooldownMs) {\n circuit.openedAt = null;\n circuit.deaths.length = 0;\n deps.log({ event: 'service_supervisor_circuit_closed' });\n return false;\n }\n return true;\n }\n\n function recordDeath(): void {\n if (!circuitEnabled) return;\n const now = deps.now();\n const cutoff = now - circuitWindowMs;\n while (circuit.deaths.length > 0) {\n const head = circuit.deaths[0];\n if (head !== undefined && head < cutoff) {\n circuit.deaths.shift();\n continue;\n }\n break;\n }\n circuit.deaths.push(now);\n if (circuit.deaths.length >= circuitMaxDeaths && circuit.openedAt === null) {\n circuit.openedAt = now;\n deps.log({\n event: 'service_supervisor_circuit_opened',\n deathCount: circuit.deaths.length,\n cooldownMs: circuitCooldownMs,\n });\n }\n }\n\n function spawn(): LiveChild<TCommand> {\n const generation = nextGeneration++;\n const proc = deps.fork(deps.workerPath, deps.workerArgs ?? [], {\n stdio: ['pipe', 'pipe', 'pipe', 'ipc'],\n });\n const peer = createStdioChildPeer<TReply, TCommand>({\n process: proc,\n generation,\n inboundCodec: deps.replyCodec,\n outboundCodec: deps.commandCodec,\n onMessage: (reply, fromGeneration) => {\n /**\n * Pass every reply through with its source generation. The supervisor\n * does NOT filter stale replies — consumers compare `fromGeneration`\n * against `supervisor.generation` and decide what to log/drop. This\n * keeps log event names domain-specific (e.g. watcher-worker emits\n * `watcher_worker_stale_reply_dropped` with its own field shape).\n */\n deps.onReply(reply, fromGeneration);\n },\n onDecodeFailed: deps.onDecodeFailed,\n onStderrLine: deps.onStderrLine,\n onMissingStdout: deps.onMissingStdout,\n onOverflow: deps.onOverflow,\n onError: deps.onPeerError,\n onExit: ({ code, signal, generation: exitGeneration }) => {\n handleExit(exitGeneration, code, signal);\n },\n });\n const holder: LiveChild<TCommand> = {\n process: proc,\n peer,\n generation,\n spawnedAt: deps.now(),\n exited: false,\n };\n deps.log({ event: 'service_supervisor_started', pid: proc.pid ?? null, generation });\n deps.onChildSpawned?.({ generation, pid: proc.pid ?? null });\n return holder;\n }\n\n function handleExit(\n exitGeneration: number,\n code: number | null,\n signal: NodeJS.Signals | null\n ): void {\n /** Drop exits from a generation we've already replaced. */\n if (live === null || exitGeneration !== live.generation) return;\n const finished = live;\n finished.exited = true;\n live = null;\n const uptimeMs = deps.now() - finished.spawnedAt;\n recordDeath();\n deps.onChildExit({ code, signal, generation: exitGeneration, uptimeMs });\n }\n\n function killCurrentIfAlive(): void {\n if (live === null) return;\n const dying = live;\n live = null;\n if (dying.exited) return;\n try {\n dying.process.kill('SIGKILL');\n } catch (err) {\n deps.log({\n event: 'service_supervisor_kill_failed',\n err: err instanceof Error ? err.message : String(err),\n });\n }\n }\n\n return {\n get generation() {\n return live?.generation ?? 0;\n },\n get healthy() {\n return live !== null && !isCircuitOpen();\n },\n get circuitOpen() {\n return isCircuitOpen();\n },\n start() {\n if (disposed) return;\n if (live !== null) return;\n live = spawn();\n },\n send(command) {\n if (live === null) return false;\n return live.peer.send(command);\n },\n restart() {\n if (disposed) return false;\n if (isCircuitOpen()) {\n deps.log({ event: 'service_supervisor_restart_blocked_circuit_open' });\n return false;\n }\n killCurrentIfAlive();\n live = spawn();\n return true;\n },\n dispose() {\n disposed = true;\n },\n getCurrentProcess() {\n return live?.process ?? null;\n },\n };\n}\n"],"mappings":"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","names":["options"]}