@deepseek-ai/dsh-ptc-runtime-node 0.1.6-alpha.1

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/lib/process.js ADDED
@@ -0,0 +1,1136 @@
1
+ import { Socket } from "node:net";
2
+ import { Buffer as Buffer$1 } from "node:buffer";
3
+ import { inspect } from "node:util";
4
+ /** Private launch marker consumed before a Node child executes application code. */
5
+ const SUBPROCESS_CONTROL_ENV = "DSH_SUBPROCESS_CONTROL";
6
+ /**
7
+ * Consume the launch marker and open the inherited control pipe at fd 7.
8
+ * The returned stream owns the descriptor. Call once before executing untrusted code;
9
+ * messages remain untrusted even though the endpoint was inherited.
10
+ * @returns a connected byte-mode duplex stream owned by the caller.
11
+ * @throws when the marker is missing/invalid or the inherited descriptor cannot be opened.
12
+ */
13
+ function openInheritedControlChannel() {
14
+ const marker = process.env[SUBPROCESS_CONTROL_ENV];
15
+ Reflect.deleteProperty(process.env, SUBPROCESS_CONTROL_ENV);
16
+ if (marker !== "pipe") throw new Error("subprocess control channel was not inherited");
17
+ return new Socket({
18
+ fd: 7,
19
+ readable: true,
20
+ writable: true,
21
+ allowHalfOpen: true
22
+ });
23
+ }
24
+ //#endregion
25
+ //#region lib/types/output-json.js
26
+ /** JSON string-prefix accounting for the outer-output ledger. @module @deepseek-ai/dsh-ptc-runtime-node/output-json */
27
+ const intrinsicReflectApply$1 = Reflect.apply;
28
+ const intrinsicArrayIsArray$1 = Array.isArray;
29
+ const IntrinsicBuffer = Buffer;
30
+ const intrinsicBufferByteLength = Reflect.get(Buffer, "byteLength");
31
+ const intrinsicObjectCreate$1 = Object.create;
32
+ const intrinsicObjectDefineProperty$1 = Object.defineProperty;
33
+ const intrinsicObjectKeys$1 = Object.keys;
34
+ const intrinsicString = String;
35
+ const intrinsicStringCharCodeAt = Reflect.get(String.prototype, "charCodeAt");
36
+ const intrinsicStringCodePointAt = Reflect.get(String.prototype, "codePointAt");
37
+ const intrinsicStringSlice = Reflect.get(String.prototype, "slice");
38
+ /** Build a data descriptor that cannot inherit model-defined accessor fields. */
39
+ function dataDescriptor$1(value) {
40
+ const descriptor = intrinsicObjectCreate$1(null);
41
+ descriptor.value = value;
42
+ return descriptor;
43
+ }
44
+ /** Define an ordinary enumerable data slot without a prototype-bearing descriptor. */
45
+ function defineEnumerableDataProperty$1(target, key, value) {
46
+ const descriptor = dataDescriptor$1(value);
47
+ descriptor.enumerable = true;
48
+ descriptor.configurable = true;
49
+ descriptor.writable = true;
50
+ intrinsicObjectDefineProperty$1(target, key, descriptor);
51
+ }
52
+ /** UTF-8 byte length through the module-captured Node intrinsic. */
53
+ function byteLength(text) {
54
+ return intrinsicReflectApply$1(intrinsicBufferByteLength, IntrinsicBuffer, [text, "utf8"]);
55
+ }
56
+ /** Append without consulting a model-mutated `Array.prototype`. */
57
+ function append$1(target, value) {
58
+ defineEnumerableDataProperty$1(target, target.length, value);
59
+ }
60
+ /** Pop without consulting a model-mutated `Array.prototype`. */
61
+ function takeLast$1(target) {
62
+ if (target.length === 0) return void 0;
63
+ const index = target.length - 1;
64
+ const value = target[index];
65
+ intrinsicObjectDefineProperty$1(target, "length", dataDescriptor$1(index));
66
+ return value;
67
+ }
68
+ /** One code-point-aligned character from a string. */
69
+ function characterAt(text, index) {
70
+ return intrinsicReflectApply$1(intrinsicStringSlice, text, [index, index + (intrinsicReflectApply$1(intrinsicStringCodePointAt, text, [index]) > 65535 ? 2 : 1)]);
71
+ }
72
+ /** Serialized bytes contributed by one complete Unicode code point inside JSON quotes. */
73
+ function serializedCharacterBytes(character) {
74
+ if (character.length === 2) return 4;
75
+ if (character === "\"" || character === "\\") return 2;
76
+ const code = intrinsicReflectApply$1(intrinsicStringCharCodeAt, character, [0]);
77
+ if (code >= 55296 && code <= 57343) return 6;
78
+ if (code < 32) return code === 8 || code === 9 || code === 10 || code === 12 || code === 13 ? 2 : 6;
79
+ return byteLength(character);
80
+ }
81
+ /**
82
+ * Measure one JSON string without materializing its complete escaped form.
83
+ * @param text - the candidate string.
84
+ * @param maxBytes - largest serialized size the caller can admit.
85
+ * @returns Exact serialized bytes, or `undefined` as soon as the cap is crossed.
86
+ */
87
+ function jsonStringBytesUpTo(text, maxBytes) {
88
+ if (maxBytes < 2) return void 0;
89
+ let bytes = 2;
90
+ for (let index = 0; index < text.length;) {
91
+ const character = characterAt(text, index);
92
+ bytes += serializedCharacterBytes(character);
93
+ if (bytes > maxBytes) return void 0;
94
+ index += character.length;
95
+ }
96
+ return bytes;
97
+ }
98
+ /**
99
+ * Measure one lossless JSON value without allocating its serialized form.
100
+ * @param value - already validated lossless JSON.
101
+ * @param maxBytes - largest serialized size the caller can admit.
102
+ * @returns Exact serialized bytes, or `undefined` as soon as the cap is crossed.
103
+ */
104
+ function jsonValueBytesUpTo(value, maxBytes) {
105
+ let bytes = 0;
106
+ const add = (cost) => {
107
+ bytes += cost;
108
+ return bytes <= maxBytes;
109
+ };
110
+ const tasks = [{
111
+ kind: "value",
112
+ value
113
+ }];
114
+ for (let task = takeLast$1(tasks); task !== void 0; task = takeLast$1(tasks)) {
115
+ if (task.kind === "value") {
116
+ const current = task.value;
117
+ if (current === null) {
118
+ if (!add(4)) return void 0;
119
+ } else if (typeof current === "string") {
120
+ const stringBytes = jsonStringBytesUpTo(current, maxBytes - bytes);
121
+ if (stringBytes === void 0) return void 0;
122
+ bytes += stringBytes;
123
+ } else if (typeof current === "number") {
124
+ if (!add(byteLength(intrinsicString(current)))) return void 0;
125
+ } else if (typeof current === "boolean") {
126
+ if (!add(current ? 4 : 5)) return void 0;
127
+ } else if (intrinsicArrayIsArray$1(current)) {
128
+ if (!add(2)) return void 0;
129
+ if (current.length > 0) append$1(tasks, {
130
+ kind: "array",
131
+ value: current,
132
+ index: 0
133
+ });
134
+ } else {
135
+ if (!add(2)) return void 0;
136
+ const keys = intrinsicObjectKeys$1(current);
137
+ if (keys.length > 0) append$1(tasks, {
138
+ kind: "object",
139
+ value: current,
140
+ keys,
141
+ index: 0
142
+ });
143
+ }
144
+ continue;
145
+ }
146
+ if (task.index > 0 && !add(1)) return void 0;
147
+ if (task.kind === "array") {
148
+ const item = task.value[task.index];
149
+ if (item === void 0) return void 0;
150
+ if (task.index + 1 < task.value.length) append$1(tasks, {
151
+ ...task,
152
+ index: task.index + 1
153
+ });
154
+ append$1(tasks, {
155
+ kind: "value",
156
+ value: item
157
+ });
158
+ continue;
159
+ }
160
+ const key = task.keys[task.index];
161
+ /* v8 ignore next -- an object frame is created and advanced only for an existing Object.keys entry. */
162
+ if (key === void 0) return void 0;
163
+ const keyBytes = jsonStringBytesUpTo(key, maxBytes - bytes);
164
+ if (keyBytes === void 0) return void 0;
165
+ if (!add(keyBytes + 1)) return void 0;
166
+ const item = task.value[key];
167
+ if (item === void 0) return void 0;
168
+ if (task.index + 1 < task.keys.length) append$1(tasks, {
169
+ ...task,
170
+ index: task.index + 1
171
+ });
172
+ append$1(tasks, {
173
+ kind: "value",
174
+ value: item
175
+ });
176
+ }
177
+ return bytes;
178
+ }
179
+ /**
180
+ * Return the longest code-point-aligned prefix whose JSON string encoding,
181
+ * including its surrounding quotes, fits `maxBytes`.
182
+ *
183
+ * @param text - the candidate string.
184
+ * @param maxBytes - serialized JSON-string bytes available.
185
+ * @returns the fitting prefix, or an empty string when even useful content cannot fit.
186
+ */
187
+ function truncateJsonStringBytes(text, maxBytes) {
188
+ if (maxBytes < 2) return "";
189
+ let bytes = 2;
190
+ let end = 0;
191
+ for (let index = 0; index < text.length;) {
192
+ const character = characterAt(text, index);
193
+ const cost = serializedCharacterBytes(character);
194
+ if (bytes + cost > maxBytes) break;
195
+ bytes += cost;
196
+ end += character.length;
197
+ index += character.length;
198
+ }
199
+ return end === text.length ? text : intrinsicReflectApply$1(intrinsicStringSlice, text, [0, end]);
200
+ }
201
+ //#endregion
202
+ //#region lib/types/channel.js
203
+ /** Length-prefixed JSON transport with bounded input and queued writes. */
204
+ const stringify = JSON.stringify;
205
+ const parse = JSON.parse;
206
+ /** One co-shipped process channel; the consumer owns frame validation and terminal outcomes. */
207
+ var JsonChannel = class {
208
+ stream;
209
+ maxBytes;
210
+ receive;
211
+ failure;
212
+ header = Buffer$1.alloc(4);
213
+ headerBytes = 0;
214
+ payload;
215
+ payloadBytes = 0;
216
+ queuedBytes = 0;
217
+ closed = false;
218
+ writes = /* @__PURE__ */ new Set();
219
+ constructor(stream, maxBytes, receive, failure) {
220
+ this.stream = stream;
221
+ this.maxBytes = maxBytes;
222
+ this.receive = receive;
223
+ this.failure = failure;
224
+ stream.on("data", this.onData);
225
+ stream.on("error", this.onError);
226
+ stream.on("end", this.onEnd);
227
+ stream.on("close", this.onClose);
228
+ }
229
+ onError = (error) => {
230
+ this.finishWrites(error);
231
+ if (!this.closed) this.failure(error, "io");
232
+ };
233
+ onClose = () => {
234
+ this.finishWrites(/* @__PURE__ */ new Error("control channel closed during a write"));
235
+ };
236
+ onEnd = () => {
237
+ if (!this.closed) this.failure(/* @__PURE__ */ new Error("control channel ended before the program settled"), "io");
238
+ };
239
+ onData = (chunk) => {
240
+ if (this.closed) return;
241
+ try {
242
+ let offset = 0;
243
+ while (offset < chunk.length && !this.closed) {
244
+ if (this.payload === void 0) {
245
+ const bytes = Math.min(4 - this.headerBytes, chunk.length - offset);
246
+ chunk.copy(this.header, this.headerBytes, offset, offset + bytes);
247
+ this.headerBytes += bytes;
248
+ offset += bytes;
249
+ if (this.headerBytes !== 4) continue;
250
+ const length = this.header.readUInt32BE(0);
251
+ if (length === 0 || length > this.maxBytes) throw new Error(`control frame exceeds ${this.maxBytes} bytes or is empty`);
252
+ this.payload = Buffer$1.allocUnsafe(length);
253
+ this.payloadBytes = 0;
254
+ this.headerBytes = 0;
255
+ }
256
+ const bytes = Math.min(this.payload.length - this.payloadBytes, chunk.length - offset);
257
+ chunk.copy(this.payload, this.payloadBytes, offset, offset + bytes);
258
+ this.payloadBytes += bytes;
259
+ offset += bytes;
260
+ if (this.payloadBytes !== this.payload.length) continue;
261
+ const frame = this.payload;
262
+ this.payload = void 0;
263
+ this.payloadBytes = 0;
264
+ this.receive(parse(new TextDecoder("utf-8", { fatal: true }).decode(frame)), frame.length);
265
+ }
266
+ } catch (error) {
267
+ this.failure(error instanceof Error ? error : new Error(String(error)), "protocol");
268
+ }
269
+ };
270
+ /**
271
+ * Submit a bounded frame immediately and await the stream's write receipt.
272
+ * @param message - JSON-only co-shipped protocol value.
273
+ * @returns Resolves when this frame has been written, or rejects after transport failure.
274
+ */
275
+ send(message) {
276
+ if (this.closed) return Promise.reject(/* @__PURE__ */ new Error("control channel is closed"));
277
+ const size = jsonValueBytesUpTo(message, this.maxBytes);
278
+ if (size === void 0 || this.queuedBytes + size > this.maxBytes) return Promise.reject(/* @__PURE__ */ new Error(`control output exceeds ${this.maxBytes} queued bytes`));
279
+ const body = Buffer$1.from(stringify(message), "utf8");
280
+ const header = Buffer$1.alloc(4);
281
+ header.writeUInt32BE(body.length);
282
+ this.queuedBytes += body.length;
283
+ const completion = Promise.withResolvers();
284
+ const write = {
285
+ promise: completion.promise,
286
+ finish: (error) => {
287
+ if (!this.writes.delete(write)) return;
288
+ this.queuedBytes -= body.length;
289
+ if (error) completion.reject(error);
290
+ else completion.resolve();
291
+ }
292
+ };
293
+ this.writes.add(write);
294
+ try {
295
+ this.stream.cork();
296
+ this.stream.write(header);
297
+ this.stream.write(body, (error) => {
298
+ write.finish(error ?? void 0);
299
+ });
300
+ this.stream.uncork();
301
+ } catch (error) {
302
+ write.finish(error instanceof Error ? error : new Error(String(error)));
303
+ }
304
+ return completion.promise;
305
+ }
306
+ finishWrites(error) {
307
+ for (const write of this.writes) write.finish(error);
308
+ }
309
+ /** Stop reads and close the owned endpoint; pending writes reject on closure. */
310
+ close() {
311
+ if (this.closed) return;
312
+ this.closed = true;
313
+ this.payload = void 0;
314
+ this.finishWrites(/* @__PURE__ */ new Error("control channel is closed"));
315
+ this.stream.off("data", this.onData);
316
+ this.stream.off("end", this.onEnd);
317
+ this.stream.destroy();
318
+ }
319
+ /** Wait for accepted writes to finish or fail. */
320
+ async drain() {
321
+ await Promise.allSettled([...this.writes].map((write) => write.promise));
322
+ }
323
+ };
324
+ //#endregion
325
+ //#region lib/types/json-wire.js
326
+ /**
327
+ * Lossless-JSON snapshots for the dependency-free source bootstrap closure.
328
+ * @module @deepseek-ai/dsh-ptc-runtime-node/json-wire
329
+ */
330
+ const intrinsicFunctionToString = Reflect.get(Function.prototype, "toString");
331
+ const intrinsicReflectApply = Reflect.get(Reflect, "apply");
332
+ const IntrinsicError = Error;
333
+ const IntrinsicSet = Set;
334
+ const intrinsicArrayIsArray = Array.isArray;
335
+ const intrinsicArrayPrototype = Array.prototype;
336
+ const intrinsicNumberIsFinite = Number.isFinite;
337
+ const intrinsicNumberIsSafeInteger = Number.isSafeInteger;
338
+ const intrinsicObjectCreate = Object.create;
339
+ const intrinsicObjectDefineProperty = Object.defineProperty;
340
+ const intrinsicObjectGetOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;
341
+ const intrinsicObjectGetPrototypeOf = Object.getPrototypeOf;
342
+ const intrinsicObjectHasOwn = Object.hasOwn;
343
+ const intrinsicObjectIs = Object.is;
344
+ const intrinsicObjectKeys = Object.keys;
345
+ const intrinsicObjectPrototype = Object.prototype;
346
+ const intrinsicObjectPropertyIsEnumerable = Reflect.get(intrinsicObjectPrototype, "propertyIsEnumerable");
347
+ const intrinsicReflectOwnKeys = Reflect.ownKeys;
348
+ const intrinsicSetAdd = Reflect.get(Set.prototype, "add");
349
+ const intrinsicSetDelete = Reflect.get(Set.prototype, "delete");
350
+ const intrinsicSetHas = Reflect.get(Set.prototype, "has");
351
+ /** Build a data descriptor that cannot inherit model-defined accessor fields. */
352
+ function dataDescriptor(value) {
353
+ const descriptor = intrinsicObjectCreate(null);
354
+ descriptor.value = value;
355
+ return descriptor;
356
+ }
357
+ /** Define an ordinary enumerable data slot without a prototype-bearing descriptor. */
358
+ function defineEnumerableDataProperty(target, key, value) {
359
+ const descriptor = dataDescriptor(value);
360
+ descriptor.enumerable = true;
361
+ descriptor.configurable = true;
362
+ descriptor.writable = true;
363
+ intrinsicObjectDefineProperty(target, key, descriptor);
364
+ }
365
+ /** Append without consulting a model-mutated `Array.prototype`. */
366
+ function append(target, value) {
367
+ defineEnumerableDataProperty(target, target.length, value);
368
+ }
369
+ /** Pop without consulting a model-mutated `Array.prototype`. */
370
+ function takeLast(target) {
371
+ if (target.length === 0) return void 0;
372
+ const index = target.length - 1;
373
+ const value = target[index];
374
+ intrinsicObjectDefineProperty(target, "length", dataDescriptor(index));
375
+ return value;
376
+ }
377
+ /** Whether one captured-intrinsic Set contains a value. */
378
+ function setHas(target, value) {
379
+ return intrinsicReflectApply(intrinsicSetHas, target, [value]);
380
+ }
381
+ /** Add to one captured-intrinsic Set. */
382
+ function setAdd(target, value) {
383
+ intrinsicReflectApply(intrinsicSetAdd, target, [value]);
384
+ }
385
+ /** Delete from one captured-intrinsic Set. */
386
+ function setDelete(target, value) {
387
+ intrinsicReflectApply(intrinsicSetDelete, target, [value]);
388
+ }
389
+ /** Whether a realm-owned intrinsic prototype is backed by its native constructor. */
390
+ function hasIntrinsicConstructor(prototype, name) {
391
+ const constructor = intrinsicObjectGetOwnPropertyDescriptor(prototype, "constructor")?.value;
392
+ if (typeof constructor !== "function") return false;
393
+ try {
394
+ return constructor.name === name && constructor.prototype === prototype && intrinsicReflectApply(intrinsicFunctionToString, constructor, []) === `function ${name}() { [native code] }`;
395
+ } catch {
396
+ return false;
397
+ }
398
+ }
399
+ /** Whether a candidate is a foreign realm's intrinsic `Object.prototype`. */
400
+ function isForeignIntrinsicObjectPrototype(value) {
401
+ return intrinsicObjectGetPrototypeOf(value) === null && hasIntrinsicConstructor(value, "Object");
402
+ }
403
+ /** Whether an array uses one realm's intrinsic `Array.prototype`, not a subclass or forged prototype. */
404
+ function hasPlainArrayPrototype(value) {
405
+ const prototype = intrinsicObjectGetPrototypeOf(value);
406
+ if (prototype === intrinsicArrayPrototype) return true;
407
+ if (!intrinsicArrayIsArray(prototype) || !hasIntrinsicConstructor(prototype, "Array")) return false;
408
+ const objectPrototype = intrinsicObjectGetPrototypeOf(prototype);
409
+ return typeof objectPrototype === "object" && objectPrototype !== null && isForeignIntrinsicObjectPrototype(objectPrototype);
410
+ }
411
+ /** Whether an object is a plain or null-prototype record from any JavaScript realm. */
412
+ function hasPlainObjectPrototype(value) {
413
+ const prototype = intrinsicObjectGetPrototypeOf(value);
414
+ return prototype === null || prototype === intrinsicObjectPrototype || typeof prototype === "object" && isForeignIntrinsicObjectPrototype(prototype);
415
+ }
416
+ /** Return every JSON-visible object key, or reject own data JSON would discard. */
417
+ function enumerableStringKeys(value) {
418
+ const keys = intrinsicReflectOwnKeys(value);
419
+ for (let index = 0; index < keys.length; index++) {
420
+ const key = keys[index];
421
+ if (typeof key !== "string" || !intrinsicReflectApply(intrinsicObjectPropertyIsEnumerable, value, [key])) return void 0;
422
+ }
423
+ return keys;
424
+ }
425
+ /**
426
+ * Validate and detach one process-boundary value without loading another
427
+ * workspace package at runtime. This mirrors the session-owned canonical
428
+ * JSON boundary while remaining safe to import from the unbuilt bootstrap.
429
+ * Its iterative traversal adds no JavaScript call-stack depth limit.
430
+ *
431
+ * @param value - the candidate completion value.
432
+ * @returns a detached lossless-JSON snapshot, or `undefined` when invalid.
433
+ */
434
+ function snapshotPtcJsonValue(value) {
435
+ const active = new IntrinsicSet();
436
+ let root;
437
+ const assign = (destination, item) => {
438
+ if (destination.kind === "root") root = item;
439
+ else if (destination.kind === "array") defineEnumerableDataProperty(destination.target, destination.index, item);
440
+ else defineEnumerableDataProperty(destination.target, destination.key, item);
441
+ };
442
+ const tasks = [{
443
+ kind: "visit",
444
+ value,
445
+ destination: { kind: "root" }
446
+ }];
447
+ for (let task = takeLast(tasks); task !== void 0; task = takeLast(tasks)) {
448
+ if (task.kind === "leave") {
449
+ setDelete(active, task.source);
450
+ continue;
451
+ }
452
+ if (task.kind === "array-item") {
453
+ if (!intrinsicObjectHasOwn(task.source, task.index)) return void 0;
454
+ append(tasks, {
455
+ kind: "visit",
456
+ value: task.source[task.index],
457
+ destination: {
458
+ kind: "array",
459
+ target: task.target,
460
+ index: task.index
461
+ }
462
+ });
463
+ continue;
464
+ }
465
+ if (task.kind === "object-property") {
466
+ append(tasks, {
467
+ kind: "visit",
468
+ value: task.source[task.key],
469
+ destination: {
470
+ kind: "object",
471
+ target: task.target,
472
+ key: task.key
473
+ }
474
+ });
475
+ continue;
476
+ }
477
+ const candidate = task.value;
478
+ if (candidate === null) {
479
+ assign(task.destination, null);
480
+ continue;
481
+ }
482
+ if (typeof candidate === "boolean" || typeof candidate === "string") {
483
+ assign(task.destination, candidate);
484
+ continue;
485
+ }
486
+ if (typeof candidate === "number") {
487
+ if (!intrinsicNumberIsFinite(candidate) || intrinsicObjectIs(candidate, -0)) return void 0;
488
+ assign(task.destination, candidate);
489
+ continue;
490
+ }
491
+ if (typeof candidate !== "object") return void 0;
492
+ if (setHas(active, candidate)) return void 0;
493
+ if (intrinsicArrayIsArray(candidate)) {
494
+ if (!hasPlainArrayPrototype(candidate)) return void 0;
495
+ const length = candidate.length;
496
+ if (intrinsicReflectOwnKeys(candidate).length !== length + 1) return void 0;
497
+ const target = [];
498
+ assign(task.destination, target);
499
+ setAdd(active, candidate);
500
+ append(tasks, {
501
+ kind: "leave",
502
+ source: candidate
503
+ });
504
+ for (let index = length - 1; index >= 0; index--) append(tasks, {
505
+ kind: "array-item",
506
+ source: candidate,
507
+ index,
508
+ target
509
+ });
510
+ continue;
511
+ }
512
+ if (!hasPlainObjectPrototype(candidate)) return void 0;
513
+ const keys = enumerableStringKeys(candidate);
514
+ if (keys === void 0) return void 0;
515
+ const target = {};
516
+ assign(task.destination, target);
517
+ setAdd(active, candidate);
518
+ append(tasks, {
519
+ kind: "leave",
520
+ source: candidate
521
+ });
522
+ for (let index = keys.length - 1; index >= 0; index--) {
523
+ const key = keys[index];
524
+ /* v8 ignore next -- the loop is bounded by the captured key count. */
525
+ if (key === void 0) return void 0;
526
+ append(tasks, {
527
+ kind: "object-property",
528
+ source: candidate,
529
+ key,
530
+ target
531
+ });
532
+ }
533
+ }
534
+ return root;
535
+ }
536
+ /**
537
+ * Flatten one validated JSON value for the process control channel.
538
+ * @param value - the lossless JSON value to transport.
539
+ * @returns a pre-order token stream whose own nesting is bounded.
540
+ */
541
+ function encodePtcJsonWire(value) {
542
+ const wire = [];
543
+ const pending = [value];
544
+ for (let current = takeLast(pending); current !== void 0; current = takeLast(pending)) {
545
+ if (current === null || typeof current === "boolean" || typeof current === "number" || typeof current === "string") {
546
+ append(wire, current);
547
+ continue;
548
+ }
549
+ if (intrinsicArrayIsArray(current)) {
550
+ append(wire, {
551
+ kind: "array",
552
+ length: current.length
553
+ });
554
+ for (let index = current.length - 1; index >= 0; index--) {
555
+ const item = current[index];
556
+ if (item === void 0) throw new IntrinsicError("cannot encode a sparse JSON array");
557
+ append(pending, item);
558
+ }
559
+ continue;
560
+ }
561
+ const keys = intrinsicObjectKeys(current);
562
+ append(wire, {
563
+ kind: "object",
564
+ keys
565
+ });
566
+ for (let index = keys.length - 1; index >= 0; index--) {
567
+ const key = keys[index];
568
+ /* v8 ignore next -- the loop is bounded by the captured key count. */
569
+ if (key === void 0) throw new IntrinsicError("cannot encode a missing JSON object key");
570
+ const item = current[key];
571
+ if (item === void 0) throw new IntrinsicError("cannot encode an undefined JSON object property");
572
+ append(pending, item);
573
+ }
574
+ }
575
+ return wire;
576
+ }
577
+ /** Whether an array contains exactly its dense indexed slots and `length`. */
578
+ function isDenseArray(value) {
579
+ if (!hasPlainArrayPrototype(value) || intrinsicReflectOwnKeys(value).length !== value.length + 1) return false;
580
+ for (let index = 0; index < value.length; index++) if (!intrinsicObjectHasOwn(value, index)) return false;
581
+ return true;
582
+ }
583
+ /** Whether one exact string-key list contains a key, without consulting its prototype. */
584
+ function keysContain(keys, expected) {
585
+ for (let index = 0; index < keys.length; index++) if (keys[index] === expected) return true;
586
+ return false;
587
+ }
588
+ /** Return one exact container marker, or reject any extra/missing fields. */
589
+ function containerToken(value) {
590
+ if (intrinsicArrayIsArray(value) || !hasPlainObjectPrototype(value)) return void 0;
591
+ const keys = enumerableStringKeys(value);
592
+ if (keys === void 0) return void 0;
593
+ const token = value;
594
+ if (token.kind === "array") {
595
+ if (keys.length !== 2 || !keysContain(keys, "kind") || !keysContain(keys, "length")) return void 0;
596
+ const length = token.length;
597
+ return typeof length === "number" && intrinsicNumberIsSafeInteger(length) && length >= 0 ? {
598
+ kind: "array",
599
+ length
600
+ } : void 0;
601
+ }
602
+ if (token.kind === "object") {
603
+ if (keys.length !== 2 || !keysContain(keys, "kind") || !keysContain(keys, "keys")) return void 0;
604
+ const objectKeys = token.keys;
605
+ if (!intrinsicArrayIsArray(objectKeys) || !isDenseArray(objectKeys)) return void 0;
606
+ const unique = new IntrinsicSet();
607
+ const normalizedKeys = [];
608
+ const objectKeyValues = objectKeys;
609
+ for (let index = 0; index < objectKeyValues.length; index++) {
610
+ const key = objectKeyValues[index];
611
+ if (typeof key !== "string" || setHas(unique, key)) return void 0;
612
+ setAdd(unique, key);
613
+ append(normalizedKeys, key);
614
+ }
615
+ return {
616
+ kind: "object",
617
+ keys: normalizedKeys
618
+ };
619
+ }
620
+ }
621
+ /**
622
+ * Rebuild one lossless JSON value from the flat process wire format.
623
+ * Malformed or incomplete traffic returns `undefined`; traversal is iterative
624
+ * and therefore independent of the transported value's application depth.
625
+ * @param input - untrusted message-port payload.
626
+ * @returns the detached JSON value, or `undefined` when the wire is invalid.
627
+ */
628
+ function decodePtcJsonWire(input) {
629
+ try {
630
+ if (!intrinsicArrayIsArray(input) || !isDenseArray(input) || input.length === 0) return void 0;
631
+ const wire = input;
632
+ const frames = [];
633
+ let root;
634
+ let rootAssigned = false;
635
+ const attach = (value) => {
636
+ const parent = frames[frames.length - 1];
637
+ if (!parent) {
638
+ if (rootAssigned) return false;
639
+ root = value;
640
+ rootAssigned = true;
641
+ return true;
642
+ }
643
+ /* v8 ignore next -- completed frames are popped before another token can attach. */
644
+ if (parent.index >= (parent.kind === "array" ? parent.length : parent.keys.length)) return false;
645
+ if (parent.kind === "array") append(parent.target, value);
646
+ else {
647
+ const key = parent.keys[parent.index];
648
+ /* v8 ignore next -- object frames are built from validated keys and their exact length. */
649
+ if (key === void 0) return false;
650
+ defineEnumerableDataProperty(parent.target, key, value);
651
+ }
652
+ parent.index += 1;
653
+ return true;
654
+ };
655
+ for (let tokenIndex = 0; tokenIndex < wire.length; tokenIndex++) {
656
+ const token = wire[tokenIndex];
657
+ let value;
658
+ let frame;
659
+ if (token === null || typeof token === "boolean" || typeof token === "string") value = token;
660
+ else if (typeof token === "number") {
661
+ if (!intrinsicNumberIsFinite(token) || intrinsicObjectIs(token, -0)) return void 0;
662
+ value = token;
663
+ } else {
664
+ if (typeof token !== "object") return void 0;
665
+ const marker = containerToken(token);
666
+ if (!marker) return void 0;
667
+ const remainingTokens = wire.length - tokenIndex - 1;
668
+ if (marker.kind === "array") {
669
+ if (marker.length > remainingTokens) return void 0;
670
+ const target = [];
671
+ value = target;
672
+ if (marker.length > 0) frame = {
673
+ kind: "array",
674
+ target,
675
+ length: marker.length,
676
+ index: 0
677
+ };
678
+ } else {
679
+ if (marker.keys.length > remainingTokens) return void 0;
680
+ const target = {};
681
+ value = target;
682
+ if (marker.keys.length > 0) frame = {
683
+ kind: "object",
684
+ target,
685
+ keys: marker.keys,
686
+ index: 0
687
+ };
688
+ }
689
+ }
690
+ if (!attach(value)) return void 0;
691
+ if (frame) append(frames, frame);
692
+ while (frames.length > 0) {
693
+ const current = frames[frames.length - 1];
694
+ /* v8 ignore next -- the loop condition guarantees a final frame. */
695
+ if (current === void 0) break;
696
+ if (current.index < (current.kind === "array" ? current.length : current.keys.length)) break;
697
+ takeLast(frames);
698
+ }
699
+ }
700
+ return frames.length === 0 ? root : void 0;
701
+ } catch {
702
+ return;
703
+ }
704
+ }
705
+ //#endregion
706
+ //#region lib/types/bootstrap.js
707
+ /**
708
+ * Program evaluation, output capture, and host binding proxies over the process channel.
709
+ * @module @deepseek-ai/dsh-ptc-runtime-node/src/bootstrap
710
+ */
711
+ const CapturedError = Error;
712
+ const capturedObjectCreate = Object.create;
713
+ const capturedObjectDefineProperty = Object.defineProperty;
714
+ /** Define one public binding-error field without consulting mutable globals or descriptor prototypes. */
715
+ function defineBindingErrorField(error, key, value) {
716
+ const attributes = capturedObjectCreate(null);
717
+ attributes.enumerable = true;
718
+ attributes.value = value;
719
+ capturedObjectDefineProperty(error, key, attributes);
720
+ }
721
+ /**
722
+ * Ordered text capture under the shared outer JSON-byte budget, delivered to
723
+ * a sink as each item lands (the real sink streams text over the port eagerly,
724
+ * so captured output survives a mid-run termination). It includes the log
725
+ * array syntax and string escaping in its accounting. Once exhausted it emits
726
+ * the fitting prefix and reports the limit once; the host turns that condition
727
+ * into an explicit `output-limit` run failure.
728
+ */
729
+ var LogBuffer = class {
730
+ bytes = 2;
731
+ entries = 0;
732
+ truncated = false;
733
+ sink;
734
+ onLimit;
735
+ maxBytes;
736
+ constructor(maxBytes, sink, onLimit = () => {}) {
737
+ this.maxBytes = maxBytes;
738
+ this.sink = sink;
739
+ this.onLimit = onLimit;
740
+ }
741
+ /**
742
+ * Emit text to the sink, charging it against the budget (drops + marks once exhausted).
743
+ * @param text - the captured text to deliver.
744
+ */
745
+ push(text) {
746
+ if (this.truncated) return;
747
+ const separatorBytes = this.entries > 0 ? 1 : 0;
748
+ const availableBytes = this.maxBytes - this.bytes - separatorBytes;
749
+ const stringBytes = jsonStringBytesUpTo(text, availableBytes);
750
+ if (stringBytes === void 0) {
751
+ this.truncated = true;
752
+ const prefix = truncateJsonStringBytes(text, availableBytes);
753
+ if (prefix.length > 0) {
754
+ const prefixBytes = jsonStringBytesUpTo(prefix, availableBytes);
755
+ /* v8 ignore next -- truncateJsonStringBytes guarantees the returned prefix fits. */
756
+ if (prefixBytes === void 0) throw new CapturedError("program output ledger produced an oversized log prefix");
757
+ this.bytes += prefixBytes + separatorBytes;
758
+ this.entries += 1;
759
+ this.sink(prefix);
760
+ }
761
+ this.onLimit();
762
+ return;
763
+ }
764
+ this.bytes += stringBytes + separatorBytes;
765
+ this.entries += 1;
766
+ this.sink(text);
767
+ }
768
+ /** Remaining exact JSON-byte budget for the completion value or failure message. */
769
+ remainingOutputBytes() {
770
+ return this.maxBytes - this.bytes;
771
+ }
772
+ };
773
+ /** The five console methods the shim captures, in the seam's level vocabulary. */
774
+ const CONSOLE_LEVELS = [
775
+ "log",
776
+ "info",
777
+ "warn",
778
+ "error",
779
+ "debug"
780
+ ];
781
+ /**
782
+ * A `console` replacement whose five leveled methods render their arguments
783
+ * `util.inspect`-style (matching real console formatting closely enough for
784
+ * a model to recognize its own output) into the buffer. Only these five
785
+ * exist — the program gets a deliberately small console, not Node's full
786
+ * console API.
787
+ * @param logs - the buffer every rendered line is pushed into.
788
+ * @returns the five-method console object handed to the program.
789
+ */
790
+ function makeConsoleShim(logs) {
791
+ const render = (args) => args.map((arg) => typeof arg === "string" ? arg : inspect(arg, INSPECT_OPTIONS)).join(" ");
792
+ const shim = Object.create(null);
793
+ for (const level of CONSOLE_LEVELS) shim[level] = (...args) => {
794
+ logs.push(render(args));
795
+ };
796
+ return shim;
797
+ }
798
+ /**
799
+ * Redirect a stream's `write` into the log buffer (the program-visible
800
+ * `process.stdout`/`process.stderr` in the Node child), so raw writes land in emission order
801
+ * alongside console output instead of racing down a pipe. It preserves Node's optional callback
802
+ * contract: the callback runs asynchronously after admission, even when the log budget drops
803
+ * the write.
804
+ *
805
+ * @param logs - the buffer captured writes are pushed into.
806
+ * @param stream - the stream whose `write` slot is patched.
807
+ * @returns the restore function (the in-process tests un-patch; the real
808
+ * child never needs to).
809
+ */
810
+ function captureStreamWrites(logs, stream) {
811
+ const original = stream.write;
812
+ stream.write = (chunk, ...rest) => {
813
+ logs.push(typeof chunk === "string" ? chunk : String(chunk));
814
+ const callback = [rest[0], rest[1]].find((arg) => typeof arg === "function");
815
+ if (callback) queueMicrotask(() => {
816
+ callback(null);
817
+ });
818
+ return true;
819
+ };
820
+ return () => {
821
+ stream.write = original;
822
+ };
823
+ }
824
+ /** Bounded inspect options: deep enough to be useful, bounded so a pathological value cannot explode the rendering. */
825
+ const INSPECT_OPTIONS = {
826
+ depth: 4,
827
+ maxArrayLength: 100,
828
+ maxStringLength: 1e4
829
+ };
830
+ /**
831
+ * Prepare the program's completion value for the done message. Only lossless
832
+ * JSON crosses, and a value that does not fit the remaining combined outer
833
+ * budget reports `output-limit`; the host revalidates hostile traffic and
834
+ * remains authoritative for native pipe writes the program shim cannot observe.
835
+ *
836
+ * @param value - the program's completion value.
837
+ * @param remainingOutputBytes - exact bytes left after captured logs.
838
+ * @param maxOutputBytes - the configured cap named in an overflow diagnostic.
839
+ * @returns the done-message fragment: `{}` for `undefined`, else a flat wire `{ value }`.
840
+ */
841
+ function prepareCompletion(value, remainingOutputBytes, maxOutputBytes = remainingOutputBytes) {
842
+ if (value === void 0) return {};
843
+ let snapshot;
844
+ try {
845
+ snapshot = snapshotPtcJsonValue(value);
846
+ } catch {
847
+ snapshot = void 0;
848
+ }
849
+ if (snapshot === void 0) return prepareFailure("invalid-output", "program completion must be lossless JSON", remainingOutputBytes, maxOutputBytes);
850
+ if (jsonValueBytesUpTo(snapshot, remainingOutputBytes) === void 0) return outputLimit(maxOutputBytes);
851
+ return { value: encodePtcJsonWire(snapshot) };
852
+ }
853
+ /** Build the fixed overflow fragment without carrying rejected variable bytes. */
854
+ function outputLimit(maxOutputBytes) {
855
+ return { error: {
856
+ kind: "output-limit",
857
+ message: `outer output exceeded ${maxOutputBytes} bytes`
858
+ } };
859
+ }
860
+ /** Admit one bounded failure message or replace it with the fixed overflow diagnostic. */
861
+ function prepareFailure(kind, message, remainingOutputBytes, maxOutputBytes) {
862
+ if (jsonStringBytesUpTo(message, remainingOutputBytes) === void 0) return outputLimit(maxOutputBytes);
863
+ return { error: {
864
+ kind,
865
+ message
866
+ } };
867
+ }
868
+ /**
869
+ * Prepare a thrown program value without sending an unbounded stack or
870
+ * string across the process channel.
871
+ * @param error - the value thrown by the program.
872
+ * @param remainingOutputBytes - exact bytes left after captured logs.
873
+ * @param maxOutputBytes - the configured cap named in an overflow diagnostic.
874
+ * @returns a bounded exception or fixed output-limit fragment.
875
+ */
876
+ function prepareException(error, remainingOutputBytes, maxOutputBytes = remainingOutputBytes) {
877
+ let message;
878
+ try {
879
+ const detail = error instanceof CapturedError ? error.stack ?? error.message : error;
880
+ message = typeof detail === "string" ? detail : String(detail);
881
+ } catch {
882
+ message = "program threw an unrenderable value";
883
+ }
884
+ return prepareFailure("exception", message, remainingOutputBytes, maxOutputBytes);
885
+ }
886
+ /**
887
+ * Materialize the real error constructor declared by one namespace.
888
+ * @param descriptor - program-global class name and member-name property.
889
+ * @returns the constructor injected into the program and used for rejections.
890
+ */
891
+ function makeBindingErrorClass(descriptor) {
892
+ return class BindingCallError extends CapturedError {
893
+ constructor(memberName, message) {
894
+ super(message);
895
+ defineBindingErrorField(this, "name", descriptor.name);
896
+ defineBindingErrorField(this, descriptor.memberNameProperty, memberName);
897
+ }
898
+ };
899
+ }
900
+ /** Create the namespace-specific rejection for one failed binding call. */
901
+ function bindingFailure(errorClass, memberName, message) {
902
+ return errorClass ? new errorClass(memberName, message) : new CapturedError(message);
903
+ }
904
+ /**
905
+ * Build each declared error class once so calls and `instanceof` share constructor identity.
906
+ * @param data - binding namespace declarations from the boot payload.
907
+ * @returns constructors keyed by their owning namespace global.
908
+ */
909
+ function makeBindingErrorClasses(data) {
910
+ const classes = /* @__PURE__ */ new Map();
911
+ for (const namespace of data.namespaces) if (namespace.errorClass) classes.set(namespace.global, makeBindingErrorClass(namespace.errorClass));
912
+ return classes;
913
+ }
914
+ /**
915
+ * Route host replies into the pending-call map: each reply settles its call
916
+ * at most once, and a reply for an unknown id (stray, or a duplicate answer
917
+ * to an id already settled) is ignored. Shared wiring between
918
+ * {@link runProgram} and the tests that exercise {@link makeNamespaces}
919
+ * standalone.
920
+ * @param port - the port whose `message` events carry the replies.
921
+ * @param pending - the id-keyed map of unsettled binding calls.
922
+ */
923
+ function wireReplies(port, pending) {
924
+ port.on("message", (message) => {
925
+ const entry = pending.get(message.id);
926
+ if (!entry) return;
927
+ pending.delete(message.id);
928
+ if (message.ok) {
929
+ const value = decodePtcJsonWire(message.value);
930
+ if (value === void 0) entry.reject(new CapturedError("binding resolution must be lossless JSON"));
931
+ else entry.resolve(value);
932
+ } else entry.reject(new CapturedError(message.message));
933
+ });
934
+ }
935
+ /**
936
+ * Build the binding namespace objects the program sees: one null-prototype global per
937
+ * namespace, each declared name an own enumerable async function that bridges over the port
938
+ * (`__proto__`/`constructor`/`toString` are ordinary keys, never prototype collisions).
939
+ * Lossy arguments reject before posting; clone failures and host failure
940
+ * replies reject only the corresponding call.
941
+ *
942
+ * @param data - the boot payload's namespace declarations (globals + names).
943
+ * @param port - the port binding calls are posted to.
944
+ * @param pending - the id-keyed map each posted call parks its handles in.
945
+ * @param nextId - the shared mutable id counter (program-issued correlation ids).
946
+ * @param errorClasses - per-namespace constructors shared with program globals.
947
+ * @returns one namespace object per declaration, in declaration order.
948
+ */
949
+ function makeNamespaces(data, port, pending, nextId, errorClasses = makeBindingErrorClasses(data)) {
950
+ return data.namespaces.map(({ global, names }) => {
951
+ const errorClass = errorClasses.get(global);
952
+ const namespace = Object.create(null);
953
+ for (const name of names) Object.defineProperty(namespace, name, {
954
+ enumerable: true,
955
+ value: (args) => {
956
+ let detached;
957
+ try {
958
+ detached = snapshotPtcJsonValue(args);
959
+ } catch {
960
+ detached = void 0;
961
+ }
962
+ if (detached === void 0) return Promise.reject(bindingFailure(errorClass, name, "binding arguments must be lossless JSON"));
963
+ return new Promise((resolve, reject) => {
964
+ const id = nextId.value++;
965
+ pending.set(id, {
966
+ resolve,
967
+ reject: (error) => {
968
+ reject(bindingFailure(errorClass, name, error.message));
969
+ }
970
+ });
971
+ try {
972
+ port.postMessage({
973
+ type: "call",
974
+ id,
975
+ global,
976
+ name,
977
+ args: encodePtcJsonWire(detached)
978
+ });
979
+ } catch (error) {
980
+ pending.delete(id);
981
+ reject(bindingFailure(errorClass, name, `binding arguments must be structured-cloneable: ${error instanceof CapturedError ? error.message : String(error)}`));
982
+ }
983
+ });
984
+ }
985
+ });
986
+ return namespace;
987
+ });
988
+ }
989
+ /**
990
+ * Run one strict async-function body, allowing top-level `await` and `return`, and post exactly
991
+ * one terminal {@link DoneMessage}; a thrown program error becomes its `error` field.
992
+ * @param port - host message port or test double.
993
+ * @param data - the boot payload the host sent.
994
+ * @param streams - stdout/stderr objects captured as program logs.
995
+ * @returns after posting the done message.
996
+ */
997
+ async function runProgram(port, data, streams) {
998
+ const logs = new LogBuffer(data.maxOutputBytes, (text) => {
999
+ port.postMessage({
1000
+ type: "log",
1001
+ text
1002
+ });
1003
+ }, () => {
1004
+ port.postMessage({ type: "output-limit" });
1005
+ });
1006
+ captureStreamWrites(logs, streams.stdout);
1007
+ captureStreamWrites(logs, streams.stderr);
1008
+ const pending = /* @__PURE__ */ new Map();
1009
+ wireReplies(port, pending);
1010
+ const nextId = { value: 1 };
1011
+ const errorClasses = makeBindingErrorClasses(data);
1012
+ const namespaces = makeNamespaces(data, port, pending, nextId, errorClasses);
1013
+ const errorClassParameters = [];
1014
+ const errorClassValues = [];
1015
+ for (const namespace of data.namespaces) {
1016
+ if (!namespace.errorClass) continue;
1017
+ errorClassParameters.push(namespace.errorClass.name);
1018
+ const errorClass = errorClasses.get(namespace.global);
1019
+ /* v8 ignore next -- makeBindingErrorClasses covers every declaration in the same data. */
1020
+ if (!errorClass) throw new CapturedError(`missing binding error class for ${namespace.global}`);
1021
+ errorClassValues.push(errorClass);
1022
+ }
1023
+ const consoleShim = makeConsoleShim(logs);
1024
+ let done;
1025
+ try {
1026
+ /* v8 ignore next -- the arrow exists only to reach the AsyncFunction constructor; it is never invoked. */
1027
+ const AsyncFunction = (async () => {}).constructor;
1028
+ done = {
1029
+ type: "done",
1030
+ ...prepareCompletion(await new AsyncFunction(...data.namespaces.map((namespace) => namespace.global), ...errorClassParameters, "console", `'use strict';\n${data.code}`)(...namespaces, ...errorClassValues, consoleShim), logs.remainingOutputBytes(), data.maxOutputBytes)
1031
+ };
1032
+ } catch (error) {
1033
+ done = {
1034
+ type: "done",
1035
+ ...prepareException(error, logs.remainingOutputBytes(), data.maxOutputBytes)
1036
+ };
1037
+ }
1038
+ port.postMessage(done);
1039
+ }
1040
+ //#endregion
1041
+ //#region lib/types/environment.js
1042
+ /** Startup variables required by native executables before model evaluation. */
1043
+ /** Native executable search, Windows system paths, and sandbox temporary paths retained in the OS environment. */
1044
+ const STARTUP_ENVIRONMENT_NAMES = new Set([
1045
+ "PATH",
1046
+ "PATHEXT",
1047
+ "SYSTEMROOT",
1048
+ "WINDIR",
1049
+ "TEMP",
1050
+ "TMP"
1051
+ ]);
1052
+ //#endregion
1053
+ //#region lib/types/process.js
1054
+ /**
1055
+ * Run one host-supplied program after the control handshake.
1056
+ * @param stream - Inherited, already-adopted control endpoint.
1057
+ * @param maxMessageBytes - Host-validated maximum frame and queued-write bytes.
1058
+ * @param processState - Environment, output streams and exit status of this Node child.
1059
+ * @returns After control output flushes and host shutdown is observed, or transport failure closes the channel.
1060
+ */
1061
+ async function runNodeMain(stream, maxMessageBytes, processState) {
1062
+ if (!Number.isSafeInteger(maxMessageBytes) || maxMessageBytes <= 0 || maxMessageBytes > 4294967295) throw new Error("invalid control message limit");
1063
+ for (const key of Object.keys(processState.env)) if (!STARTUP_ENVIRONMENT_NAMES.has(key.toUpperCase())) Reflect.deleteProperty(processState.env, key);
1064
+ processState.env = Object.create(null);
1065
+ const boot = Promise.withResolvers();
1066
+ const listeners = [];
1067
+ let started = false;
1068
+ let failed = false;
1069
+ let terminalSent = false;
1070
+ const hostClosed = Promise.withResolvers();
1071
+ const onClose = () => {
1072
+ hostClosed.resolve();
1073
+ };
1074
+ stream.once("close", onClose);
1075
+ const channel = new JsonChannel(stream, maxMessageBytes, (raw) => {
1076
+ if (!started) {
1077
+ started = true;
1078
+ if (typeof raw !== "object" || raw === null || raw.type !== "boot") {
1079
+ boot.reject(/* @__PURE__ */ new Error("expected program boot frame"));
1080
+ return;
1081
+ }
1082
+ boot.resolve(raw.data);
1083
+ return;
1084
+ }
1085
+ if (terminalSent) return;
1086
+ for (const listener of listeners) listener(raw);
1087
+ }, (error, kind) => {
1088
+ if (!terminalSent || kind === "protocol") {
1089
+ failed = true;
1090
+ boot.reject(error);
1091
+ channel.close();
1092
+ processState.exitCode = 1;
1093
+ }
1094
+ hostClosed.resolve();
1095
+ });
1096
+ const pending = /* @__PURE__ */ new Set();
1097
+ const send = (message) => {
1098
+ if (terminalSent) return;
1099
+ if (message.type === "done") terminalSent = true;
1100
+ const task = channel.send(message).catch(() => {
1101
+ failed = true;
1102
+ channel.close();
1103
+ processState.exitCode = 1;
1104
+ hostClosed.resolve();
1105
+ }).finally(() => {
1106
+ pending.delete(task);
1107
+ });
1108
+ pending.add(task);
1109
+ };
1110
+ try {
1111
+ await channel.send({ type: "ready" });
1112
+ const data = await boot.promise;
1113
+ await runProgram({
1114
+ postMessage: send,
1115
+ on: (_event, listener) => {
1116
+ listeners.push(listener);
1117
+ }
1118
+ }, data, {
1119
+ stdout: processState.stdout,
1120
+ stderr: processState.stderr
1121
+ });
1122
+ while (pending.size > 0) await Promise.all(pending);
1123
+ await channel.drain();
1124
+ await hostClosed.promise;
1125
+ } finally {
1126
+ stream.off("close", onClose);
1127
+ channel.close();
1128
+ if (failed) processState.exitCode = 1;
1129
+ }
1130
+ }
1131
+ //#endregion
1132
+ //#region lib/types/process-entry.js
1133
+ /** Private built Node-runtime child entry; source execution calls runNodeMain directly. */
1134
+ runNodeMain(openInheritedControlChannel(), Number(process.argv[2]), process);
1135
+ //#endregion
1136
+ export {};