@alpacakit/agents 0.1.0-beta.35 → 0.1.0-beta.36

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 (50) hide show
  1. package/README.md +25 -0
  2. package/dist/agents/claude.d.ts +9 -2
  3. package/dist/agents/claude.d.ts.map +1 -1
  4. package/dist/agents/claude.js +16 -5
  5. package/dist/agents/codex.d.ts +1 -1
  6. package/dist/agents/codex.js +1 -1
  7. package/dist/core/error.d.ts +25 -0
  8. package/dist/core/error.d.ts.map +1 -1
  9. package/dist/core/error.js +15 -0
  10. package/dist/core/node-controlled-exec.d.ts.map +1 -1
  11. package/dist/core/node-controlled-exec.js +31 -8
  12. package/dist/core/node-ports.d.ts.map +1 -1
  13. package/dist/core/node-ports.js +20 -0
  14. package/dist/core/ports.d.ts +5 -0
  15. package/dist/core/ports.d.ts.map +1 -1
  16. package/dist/fleet/policy.d.ts.map +1 -1
  17. package/dist/fleet/policy.js +3 -0
  18. package/dist/index.d.ts +3 -3
  19. package/dist/index.d.ts.map +1 -1
  20. package/dist/index.js +2 -2
  21. package/dist/internal/controlled-process/host-controller.d.ts +3 -2
  22. package/dist/internal/controlled-process/host-controller.d.ts.map +1 -1
  23. package/dist/internal/controlled-process/host-controller.js +63 -23
  24. package/dist/internal/controlled-process/input-transport.d.ts +17 -0
  25. package/dist/internal/controlled-process/input-transport.d.ts.map +1 -0
  26. package/dist/internal/controlled-process/input-transport.js +188 -0
  27. package/dist/internal/controlled-process/lifecycle.d.ts +1 -1
  28. package/dist/internal/controlled-process/lifecycle.d.ts.map +1 -1
  29. package/dist/internal/controlled-process/lifecycle.js +1 -0
  30. package/dist/internal/controlled-process/schema.d.ts +2 -2
  31. package/dist/internal/controlled-process/schema.js +1 -1
  32. package/dist/internal/controlled-process/shim-runtime.d.ts.map +1 -1
  33. package/dist/internal/controlled-process/shim-runtime.js +43 -4
  34. package/dist/internal/controlled-process/supervisor-coordinator.d.ts.map +1 -1
  35. package/dist/internal/controlled-process/supervisor-coordinator.js +4 -2
  36. package/dist/internal/controlled-process/supervisor-model.d.ts +24 -2
  37. package/dist/internal/controlled-process/supervisor-model.d.ts.map +1 -1
  38. package/dist/internal/controlled-process/supervisor-runtime.d.ts.map +1 -1
  39. package/dist/internal/controlled-process/supervisor-runtime.js +116 -15
  40. package/dist/internal/controlled-process/supervisor-schema.d.ts +66 -3
  41. package/dist/internal/controlled-process/supervisor-schema.d.ts.map +1 -1
  42. package/dist/internal/controlled-process/supervisor-schema.js +31 -3
  43. package/dist/internal/controlled-process/supervisor-values.d.ts +5 -0
  44. package/dist/internal/controlled-process/supervisor-values.d.ts.map +1 -1
  45. package/dist/internal/controlled-process/supervisor-values.js +5 -0
  46. package/dist/internal/controlled-process/values.d.ts +4 -4
  47. package/dist/internal/controlled-process/values.js +4 -4
  48. package/dist/structured/run-structured.d.ts.map +1 -1
  49. package/dist/structured/run-structured.js +2 -5
  50. package/package.json +2 -2
@@ -1,7 +1,9 @@
1
1
  // biome-ignore-all lint/nursery/noExcessiveLinesPerFile: Section 5.103 confines the correction to this existing host lifecycle owner.
2
2
  import { spawn } from "node:child_process";
3
3
  import { CHILD_PROCESS_ABSENCE_PROOF, CHILD_PROCESS_TERMINATION_EVIDENCE_KIND, CHILD_PROCESS_TERMINATION_KIND, CHILD_PROCESS_UNKILLABLE_REASON, } from "../../core/controlled-process.js";
4
+ import { CONTROLLED_PROCESS_LAUNCH_FAILURE_RETRYABILITY } from "../../core/error.js";
4
5
  import { readFramedRecords, readRequiredFrame, writeFramedRecord, } from "./framed-transport.js";
6
+ import { ControlledProcessLaunchError, workerInputManifest, writeWorkerInput, } from "./input-transport.js";
5
7
  import { transitionControlledProcess } from "./lifecycle.js";
6
8
  import { controlledProcessRecordMatchesToken, signControlledProcessRecord, verifySignedControlledProcessRecord, } from "./record.js";
7
9
  import { assertSecureRuntimeDirectory, resolveSupervisorSocketNamespace, SignedRecordStore, supervisorSocketPath, } from "./record-store.js";
@@ -14,6 +16,7 @@ import { decodeProcessStartToken } from "./token.js";
14
16
  import { CONTROLLED_PROCESS_STATE } from "./values.js";
15
17
  const HOST_BOOTSTRAP_FD = 3;
16
18
  const HOST_IDENTITY_FD = 4;
19
+ const HOST_INPUT_FD = 5;
17
20
  const OUTPUT_QUEUE_HIGH_WATER_BYTES = 64 * 1024;
18
21
  const OUTPUT_QUEUE_LOW_WATER_BYTES = 32 * 1024;
19
22
  const PRE_READY_CLEANUP_AUTHORITY = {
@@ -29,8 +32,9 @@ const TERMINATION_OBSERVATION_SOURCE = {
29
32
  supervisorClose: "supervisor_close",
30
33
  offlineFallback: "offline_fallback",
31
34
  };
32
- class SupervisorReportedLaunchFailure extends Error {
35
+ class SupervisorReportedLaunchFailure extends ControlledProcessLaunchError {
33
36
  }
37
+ // biome-ignore lint/complexity/noExcessiveLinesPerFunction: Launch, readiness, and pre-ready cleanup share one custody scope.
34
38
  export async function launchControlledProcess(input) {
35
39
  const platform = createSupervisorPlatformAdapter();
36
40
  const runtimeDirectory = await assertSecureRuntimeDirectory(input.runtimeDirectory, platform.uid);
@@ -39,6 +43,7 @@ export async function launchControlledProcess(input) {
39
43
  void supervisorClose.promise.catch(() => undefined);
40
44
  const control = supervisor.stdio[HOST_BOOTSTRAP_FD];
41
45
  const identityStream = supervisor.stdio[HOST_IDENTITY_FD];
46
+ const inputStream = supervisor.stdio.at(HOST_INPUT_FD);
42
47
  const identityFrames = readFramedRecords(identityStream)[Symbol.asyncIterator]();
43
48
  let output = null;
44
49
  let identity = null;
@@ -50,29 +55,52 @@ export async function launchControlledProcess(input) {
50
55
  kind: SUPERVISOR_BOOTSTRAP_FRAME_KIND.bootstrap,
51
56
  runtimeDirectory,
52
57
  shimEntryPath: input.shimEntryPath,
53
- worker: input.worker,
58
+ worker: {
59
+ command: input.worker.command,
60
+ args: input.worker.args,
61
+ cwd: input.worker.cwd,
62
+ env: input.worker.env,
63
+ },
64
+ input: workerInputManifest(input.worker.stdin),
54
65
  timing: input.timing,
55
66
  });
67
+ const inputTransfer = writeWorkerInput(inputStream, input.worker.stdin);
68
+ void inputTransfer.catch(() => undefined);
56
69
  identity = await readSupervisorIdentity(identityFrames);
57
- let hostAckComplete = false;
58
- const readinessObservation = observeSupervisorReadiness(identityFrames, () => hostAckComplete);
70
+ let hostAckWriteStarted = false;
71
+ const readinessObservation = observeSupervisorReadiness(identityFrames, () => hostAckWriteStarted);
59
72
  await input.lifecycle.beforeExec(identity);
60
73
  descriptorCommitted = true;
74
+ hostAckWriteStarted = true;
61
75
  await writeFramedRecord(control, {
62
76
  kind: SUPERVISOR_BOOTSTRAP_FRAME_KIND.hostAck,
63
77
  });
64
- hostAckComplete = true;
65
78
  control.end();
66
- const readiness = await concludeSupervisorReadiness({
67
- observation: readinessObservation,
68
- identity,
69
- runtimeDirectory,
70
- supervisorClose,
71
- timing: input.timing,
72
- });
79
+ const [inputSettlement, readinessSettlement] = await Promise.allSettled([
80
+ inputTransfer,
81
+ concludeSupervisorReadiness({
82
+ observation: readinessObservation,
83
+ identity,
84
+ runtimeDirectory,
85
+ supervisorClose,
86
+ timing: input.timing,
87
+ }),
88
+ ]);
89
+ if (readinessSettlement.status === "rejected") {
90
+ throw readinessSettlement.reason;
91
+ }
92
+ const readiness = readinessSettlement.value;
73
93
  if (readiness.kind === "failure") {
74
94
  cleanupAuthority = readiness.cleanupAuthority;
75
- throw readiness.error;
95
+ if (readiness.error instanceof SupervisorReportedLaunchFailure) {
96
+ throw readiness.error;
97
+ }
98
+ throw inputSettlement.status === "rejected"
99
+ ? inputSettlement.reason
100
+ : readiness.error;
101
+ }
102
+ if (inputSettlement.status === "rejected") {
103
+ throw inputSettlement.reason;
76
104
  }
77
105
  const readyIdentity = identity;
78
106
  let terminationRequested = false;
@@ -101,12 +129,14 @@ export async function launchControlledProcess(input) {
101
129
  };
102
130
  }
103
131
  catch (primaryFailure) {
104
- if (primaryFailure instanceof SupervisorReportedLaunchFailure) {
132
+ if (primaryFailure instanceof SupervisorReportedLaunchFailure &&
133
+ identity === null) {
105
134
  cleanupAuthority = PRE_READY_CLEANUP_AUTHORITY.reportedFailure;
106
135
  }
107
136
  try {
108
137
  await cleanupPreReadySupervisor({
109
138
  control,
139
+ inputStream,
110
140
  identity,
111
141
  descriptorCommitted,
112
142
  runtimeDirectory,
@@ -118,26 +148,32 @@ export async function launchControlledProcess(input) {
118
148
  });
119
149
  }
120
150
  catch (cleanupFailure) {
151
+ if (primaryFailure instanceof ControlledProcessLaunchError) {
152
+ throw new ControlledProcessLaunchError({
153
+ ...primaryFailure.failure,
154
+ retryability: CONTROLLED_PROCESS_LAUNCH_FAILURE_RETRYABILITY.permanent,
155
+ }, new AggregateError([primaryFailure, cleanupFailure], `Controlled process launch and pre-ready cleanup both failed (${cleanupAuthority}).`));
156
+ }
121
157
  throw new AggregateError([primaryFailure, cleanupFailure], "Controlled process launch and pre-ready cleanup both failed.");
122
158
  }
123
159
  throw primaryFailure;
124
160
  }
125
161
  }
126
- function observeSupervisorReadiness(frames, hostAckComplete) {
162
+ function observeSupervisorReadiness(frames, hostAckWriteStarted) {
127
163
  return frames.next().then((result) => ({
128
164
  kind: "result",
129
165
  result,
130
- observedBeforeHostAck: !hostAckComplete(),
166
+ observedBeforeHostAckWrite: !hostAckWriteStarted(),
131
167
  }), (error) => ({
132
168
  kind: "failure",
133
169
  error,
134
- observedBeforeHostAck: !hostAckComplete(),
170
+ observedBeforeHostAckWrite: !hostAckWriteStarted(),
135
171
  }));
136
172
  }
137
173
  async function concludeSupervisorReadiness(input) {
138
174
  const observation = await input.observation;
139
- if (observation.observedBeforeHostAck) {
140
- return readinessFailure(new Error("Supervisor readiness arrived before host ACK completed."), PRE_READY_CLEANUP_AUTHORITY.unprobed);
175
+ if (observation.observedBeforeHostAckWrite) {
176
+ return readinessFailure(new Error("Supervisor readiness arrived before the host ACK write began."), PRE_READY_CLEANUP_AUTHORITY.unprobed);
141
177
  }
142
178
  if (observation.kind === "failure") {
143
179
  return readinessFailure(observation.error, PRE_READY_CLEANUP_AUTHORITY.unprobed);
@@ -145,7 +181,7 @@ async function concludeSupervisorReadiness(input) {
145
181
  if (!observation.result.done) {
146
182
  const failure = supervisorLaunchFailedFrameSchema.safeParse(observation.result.value);
147
183
  if (failure.success) {
148
- return readinessFailure(new Error(failure.data.reason), PRE_READY_CLEANUP_AUTHORITY.rollbackCompleted);
184
+ return readinessFailure(new SupervisorReportedLaunchFailure(failure.data.failure), PRE_READY_CLEANUP_AUTHORITY.live);
149
185
  }
150
186
  return readinessFailure(new Error("Supervisor readiness frame is invalid."), PRE_READY_CLEANUP_AUTHORITY.unprobed);
151
187
  }
@@ -209,6 +245,9 @@ async function cleanupPreReadySupervisor(input) {
209
245
  if (!input.control.destroyed && !input.control.writableEnded) {
210
246
  input.control.end();
211
247
  }
248
+ if (!input.inputStream.destroyed && !input.inputStream.writableEnded) {
249
+ input.inputStream.destroy();
250
+ }
212
251
  if (input.output !== null) {
213
252
  await input.output.queue[Symbol.asyncIterator]().return?.();
214
253
  }
@@ -377,7 +416,8 @@ async function raceSupervisorRequestWithClose(input) {
377
416
  return result;
378
417
  }
379
418
  function preReadyCleanupDeadline(timing) {
380
- const budget = Math.min(Number.MAX_SAFE_INTEGER, timing.termGraceMs + timing.killProbeTimeoutMs + timing.probeIntervalMs);
419
+ const budget = Math.min(Number.MAX_SAFE_INTEGER, (timing.termGraceMs + timing.killProbeTimeoutMs + timing.probeIntervalMs) *
420
+ 2);
381
421
  return Math.min(Number.MAX_SAFE_INTEGER, Date.now() + budget);
382
422
  }
383
423
  function beforeDeadline(operation, deadline, message) {
@@ -716,7 +756,7 @@ function spawnSupervisor(entryPath) {
716
756
  const child = spawn(process.execPath, [entryPath], {
717
757
  detached: true,
718
758
  env: {},
719
- stdio: ["ignore", "pipe", "pipe", "pipe", "pipe"],
759
+ stdio: ["ignore", "pipe", "pipe", "pipe", "pipe", "pipe"],
720
760
  });
721
761
  containSupervisorStdioErrors(child);
722
762
  child.once("error", () => { });
@@ -777,7 +817,7 @@ async function readSupervisorIdentity(frames) {
777
817
  }
778
818
  const failure = supervisorLaunchFailedFrameSchema.safeParse(frame);
779
819
  if (failure.success) {
780
- throw new SupervisorReportedLaunchFailure(failure.data.reason);
820
+ throw new SupervisorReportedLaunchFailure(failure.data.failure);
781
821
  }
782
822
  throw new Error("Supervisor identity frame is invalid.");
783
823
  }
@@ -0,0 +1,17 @@
1
+ import type { Readable, Writable } from "node:stream";
2
+ import type { ControlledProcessLaunchFailure, WorkerInputManifest } from "./supervisor-model.js";
3
+ export declare class ControlledProcessLaunchError extends Error {
4
+ readonly failure: ControlledProcessLaunchFailure;
5
+ constructor(failure: ControlledProcessLaunchFailure, cause?: unknown);
6
+ }
7
+ export declare function workerInputManifest(input: string | null): WorkerInputManifest;
8
+ export declare function writeWorkerInput(writable: Writable, input: string | null): Promise<void>;
9
+ export declare function transferWorkerInput(input: {
10
+ readonly readable: Readable;
11
+ readonly writable: Writable;
12
+ readonly manifest: WorkerInputManifest;
13
+ readonly stage: ControlledProcessLaunchFailure["stage"];
14
+ readonly timeoutMs: number;
15
+ }): Promise<void>;
16
+ export declare function launchFailure(code: ControlledProcessLaunchFailure["code"], stage: ControlledProcessLaunchFailure["stage"], expectedBytes: number | null, actualBytes: number | null, message: string, cause?: unknown): ControlledProcessLaunchError;
17
+ //# sourceMappingURL=input-transport.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"input-transport.d.ts","sourceRoot":"","sources":["../../../src/internal/controlled-process/input-transport.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAKtD,OAAO,KAAK,EACV,8BAA8B,EAC9B,mBAAmB,EACpB,MAAM,uBAAuB,CAAC;AAK/B,qBAAa,4BAA6B,SAAQ,KAAK;IACrD,QAAQ,CAAC,OAAO,EAAE,8BAA8B,CAAC;gBAErC,OAAO,EAAE,8BAA8B,EAAE,KAAK,CAAC,EAAE,OAAO;CAKrE;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,mBAAmB,CAU7E;AAED,wBAAsB,gBAAgB,CACpC,QAAQ,EAAE,QAAQ,EAClB,KAAK,EAAE,MAAM,GAAG,IAAI,GACnB,OAAO,CAAC,IAAI,CAAC,CAiBf;AAED,wBAAsB,mBAAmB,CAAC,KAAK,EAAE;IAC/C,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;IAC5B,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;IAC5B,QAAQ,CAAC,QAAQ,EAAE,mBAAmB,CAAC;IACvC,QAAQ,CAAC,KAAK,EAAE,8BAA8B,CAAC,OAAO,CAAC,CAAC;IACxD,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B,GAAG,OAAO,CAAC,IAAI,CAAC,CAuGhB;AAED,wBAAgB,aAAa,CAC3B,IAAI,EAAE,8BAA8B,CAAC,MAAM,CAAC,EAC5C,KAAK,EAAE,8BAA8B,CAAC,OAAO,CAAC,EAC9C,aAAa,EAAE,MAAM,GAAG,IAAI,EAC5B,WAAW,EAAE,MAAM,GAAG,IAAI,EAC1B,OAAO,EAAE,MAAM,EACf,KAAK,CAAC,EAAE,OAAO,GACd,4BAA4B,CAW9B"}
@@ -0,0 +1,188 @@
1
+ import { createHash } from "node:crypto";
2
+ import { CONTROLLED_PROCESS_LAUNCH_FAILURE_CODE, CONTROLLED_PROCESS_LAUNCH_FAILURE_RETRYABILITY, } from "../../core/error.js";
3
+ import { WORKER_INPUT_KIND } from "./supervisor-values.js";
4
+ const SHA256_HEX_PATTERN = /^[a-f0-9]{64}$/u;
5
+ export class ControlledProcessLaunchError extends Error {
6
+ failure;
7
+ constructor(failure, cause) {
8
+ super(failure.message, cause === undefined ? undefined : { cause });
9
+ this.name = "ControlledProcessLaunchError";
10
+ this.failure = failure;
11
+ }
12
+ }
13
+ export function workerInputManifest(input) {
14
+ if (input === null) {
15
+ return { kind: WORKER_INPUT_KIND.none };
16
+ }
17
+ const bytes = Buffer.from(input, "utf8");
18
+ return {
19
+ kind: WORKER_INPUT_KIND.stream,
20
+ byteLength: bytes.byteLength,
21
+ sha256: createHash("sha256").update(bytes).digest("hex"),
22
+ };
23
+ }
24
+ export async function writeWorkerInput(writable, input) {
25
+ const bytes = input === null ? Buffer.alloc(0) : Buffer.from(input, "utf8");
26
+ try {
27
+ if (bytes.byteLength > 0) {
28
+ await writeChunk(writable, bytes);
29
+ }
30
+ await endWritable(writable);
31
+ }
32
+ catch (error) {
33
+ throw launchFailure(CONTROLLED_PROCESS_LAUNCH_FAILURE_CODE.inputWriteFailed, "host_to_supervisor", bytes.byteLength, null, "Worker input data channel failed while writing.", error);
34
+ }
35
+ }
36
+ export async function transferWorkerInput(input) {
37
+ const expectedBytes = input.manifest.kind === WORKER_INPUT_KIND.none
38
+ ? 0
39
+ : input.manifest.byteLength;
40
+ const expectedDigest = input.manifest.kind === WORKER_INPUT_KIND.none
41
+ ? null
42
+ : input.manifest.sha256;
43
+ let actualBytes = 0;
44
+ const digest = createHash("sha256");
45
+ let timeout = null;
46
+ let timeoutFailure = null;
47
+ const transfer = transferWorkerInputBytes();
48
+ void transfer.catch(() => undefined);
49
+ try {
50
+ await Promise.race([
51
+ transfer,
52
+ new Promise((_resolve, reject) => {
53
+ timeout = setTimeout(() => {
54
+ timeoutFailure = launchFailure(CONTROLLED_PROCESS_LAUNCH_FAILURE_CODE.inputTransferTimeout, input.stage, expectedBytes, actualBytes, "Worker input transfer exceeded its launch deadline.");
55
+ input.readable.destroy();
56
+ input.writable.destroy();
57
+ reject(timeoutFailure);
58
+ }, input.timeoutMs);
59
+ }),
60
+ ]);
61
+ }
62
+ catch (error) {
63
+ if (timeoutFailure !== null) {
64
+ throw timeoutFailure;
65
+ }
66
+ throw error;
67
+ }
68
+ finally {
69
+ if (timeout !== null) {
70
+ clearTimeout(timeout);
71
+ }
72
+ }
73
+ async function transferWorkerInputBytes() {
74
+ try {
75
+ for await (const rawChunk of input.readable) {
76
+ const chunk = Buffer.isBuffer(rawChunk)
77
+ ? rawChunk
78
+ : Buffer.from(String(rawChunk), "utf8");
79
+ actualBytes += chunk.byteLength;
80
+ if (actualBytes > expectedBytes) {
81
+ throw launchFailure(CONTROLLED_PROCESS_LAUNCH_FAILURE_CODE.inputOverrun, input.stage, expectedBytes, actualBytes, "Worker input contained bytes beyond its declared length.");
82
+ }
83
+ digest.update(chunk);
84
+ if (chunk.byteLength > 0) {
85
+ await writeChunk(input.writable, chunk);
86
+ }
87
+ }
88
+ if (actualBytes !== expectedBytes) {
89
+ throw launchFailure(CONTROLLED_PROCESS_LAUNCH_FAILURE_CODE.inputEarlyEof, input.stage, expectedBytes, actualBytes, "Worker input ended before its declared length.");
90
+ }
91
+ if (expectedDigest !== null &&
92
+ (!SHA256_HEX_PATTERN.test(expectedDigest) ||
93
+ digest.digest("hex") !== expectedDigest)) {
94
+ throw launchFailure(CONTROLLED_PROCESS_LAUNCH_FAILURE_CODE.inputDigestMismatch, input.stage, expectedBytes, actualBytes, "Worker input did not match its declared SHA-256 digest.");
95
+ }
96
+ await endWritable(input.writable);
97
+ }
98
+ catch (error) {
99
+ input.writable.destroy();
100
+ if (error instanceof ControlledProcessLaunchError) {
101
+ throw error;
102
+ }
103
+ throw launchFailure(CONTROLLED_PROCESS_LAUNCH_FAILURE_CODE.inputWriteFailed, input.stage, expectedBytes, actualBytes, "Worker input data channel failed during transfer.", error);
104
+ }
105
+ }
106
+ }
107
+ export function launchFailure(code, stage, expectedBytes, actualBytes, message, cause) {
108
+ const retryability = code === CONTROLLED_PROCESS_LAUNCH_FAILURE_CODE.inputWriteFailed ||
109
+ code === CONTROLLED_PROCESS_LAUNCH_FAILURE_CODE.inputTransferTimeout ||
110
+ code === CONTROLLED_PROCESS_LAUNCH_FAILURE_CODE.workerExited
111
+ ? CONTROLLED_PROCESS_LAUNCH_FAILURE_RETRYABILITY.transient
112
+ : CONTROLLED_PROCESS_LAUNCH_FAILURE_RETRYABILITY.permanent;
113
+ return new ControlledProcessLaunchError({ code, retryability, stage, expectedBytes, actualBytes, message }, cause);
114
+ }
115
+ function writeChunk(writable, chunk) {
116
+ return new Promise((resolve, reject) => {
117
+ let settled = false;
118
+ const cleanup = () => {
119
+ writable.off("error", failed);
120
+ writable.off("close", closed);
121
+ };
122
+ const settle = (error) => {
123
+ if (settled)
124
+ return;
125
+ settled = true;
126
+ cleanup();
127
+ if (error === null) {
128
+ resolve();
129
+ return;
130
+ }
131
+ reject(error);
132
+ };
133
+ const failed = (error) => settle(error);
134
+ const closed = () => settle(new Error("Worker input writable closed during write."));
135
+ writable.once("error", failed);
136
+ writable.once("close", closed);
137
+ if (writable.destroyed || writable.closed || writable.writableEnded) {
138
+ closed();
139
+ return;
140
+ }
141
+ try {
142
+ writable.write(chunk, (error) => settle(error ?? null));
143
+ }
144
+ catch (error) {
145
+ settle(error instanceof Error
146
+ ? error
147
+ : new Error("Worker input writable write failed."));
148
+ }
149
+ });
150
+ }
151
+ function endWritable(writable) {
152
+ if (writable.destroyed || writable.closed) {
153
+ return Promise.reject(new Error("Worker input writable closed before end settlement."));
154
+ }
155
+ if (writable.writableFinished) {
156
+ return Promise.resolve();
157
+ }
158
+ return new Promise((resolve, reject) => {
159
+ let settled = false;
160
+ const cleanup = () => {
161
+ writable.off("error", failed);
162
+ writable.off("close", closed);
163
+ };
164
+ const settle = (error) => {
165
+ if (settled)
166
+ return;
167
+ settled = true;
168
+ cleanup();
169
+ if (error === null) {
170
+ resolve();
171
+ return;
172
+ }
173
+ reject(error);
174
+ };
175
+ const failed = (error) => settle(error);
176
+ const closed = () => settle(new Error("Worker input writable closed before end settlement."));
177
+ writable.once("error", failed);
178
+ writable.once("close", closed);
179
+ try {
180
+ writable.end((error) => settle(error ?? null));
181
+ }
182
+ catch (error) {
183
+ settle(error instanceof Error
184
+ ? error
185
+ : new Error("Worker input writable end failed."));
186
+ }
187
+ });
188
+ }
@@ -1,5 +1,5 @@
1
1
  import type { ControlledProcessState } from "./model.js";
2
- export declare const CONTROLLED_PROCESS_TRANSITIONS: readonly [readonly ["reserved", "acked"], readonly ["reserved", "absent"], readonly ["acked", "running"], readonly ["acked", "absent"], readonly ["running", "term"], readonly ["running", "absent"], readonly ["term", "kill_sent"], readonly ["term", "absent"], readonly ["kill_sent", "absent"], readonly ["absent", "released"]];
2
+ export declare const CONTROLLED_PROCESS_TRANSITIONS: readonly [readonly ["reserved", "acked"], readonly ["reserved", "absent"], readonly ["acked", "running"], readonly ["acked", "term"], readonly ["acked", "absent"], readonly ["running", "term"], readonly ["running", "absent"], readonly ["term", "kill_sent"], readonly ["term", "absent"], readonly ["kill_sent", "absent"], readonly ["absent", "released"]];
3
3
  export declare function isControlledProcessTransitionAllowed(from: ControlledProcessState, to: ControlledProcessState): boolean;
4
4
  export declare function transitionControlledProcess(from: ControlledProcessState, to: ControlledProcessState): ControlledProcessState;
5
5
  //# sourceMappingURL=lifecycle.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"lifecycle.d.ts","sourceRoot":"","sources":["../../../src/internal/controlled-process/lifecycle.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;AAQzD,eAAO,MAAM,8BAA8B,uUAWgB,CAAC;AAE5D,wBAAgB,oCAAoC,CAClD,IAAI,EAAE,sBAAsB,EAC5B,EAAE,EAAE,sBAAsB,GACzB,OAAO,CAIT;AAED,wBAAgB,2BAA2B,CACzC,IAAI,EAAE,sBAAsB,EAC5B,EAAE,EAAE,sBAAsB,GACzB,sBAAsB,CAKxB"}
1
+ {"version":3,"file":"lifecycle.d.ts","sourceRoot":"","sources":["../../../src/internal/controlled-process/lifecycle.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;AAQzD,eAAO,MAAM,8BAA8B,mWAYgB,CAAC;AAE5D,wBAAgB,oCAAoC,CAClD,IAAI,EAAE,sBAAsB,EAC5B,EAAE,EAAE,sBAAsB,GACzB,OAAO,CAIT;AAED,wBAAgB,2BAA2B,CACzC,IAAI,EAAE,sBAAsB,EAC5B,EAAE,EAAE,sBAAsB,GACzB,sBAAsB,CAKxB"}
@@ -3,6 +3,7 @@ export const CONTROLLED_PROCESS_TRANSITIONS = [
3
3
  [CONTROLLED_PROCESS_STATE.reserved, CONTROLLED_PROCESS_STATE.acked],
4
4
  [CONTROLLED_PROCESS_STATE.reserved, CONTROLLED_PROCESS_STATE.absent],
5
5
  [CONTROLLED_PROCESS_STATE.acked, CONTROLLED_PROCESS_STATE.running],
6
+ [CONTROLLED_PROCESS_STATE.acked, CONTROLLED_PROCESS_STATE.term],
6
7
  [CONTROLLED_PROCESS_STATE.acked, CONTROLLED_PROCESS_STATE.absent],
7
8
  [CONTROLLED_PROCESS_STATE.running, CONTROLLED_PROCESS_STATE.term],
8
9
  [CONTROLLED_PROCESS_STATE.running, CONTROLLED_PROCESS_STATE.absent],
@@ -30,7 +30,7 @@ export declare const controlledProcessIdentitySchema: z.ZodReadonly<z.ZodObject<
30
30
  processStartToken: z.ZodPipe<z.ZodString, z.ZodTransform<ProcessStartToken, string>>;
31
31
  }, z.core.$strip>>;
32
32
  export declare const controlledProcessRecordSchema: z.ZodReadonly<z.ZodObject<{
33
- protocolVersion: z.ZodLiteral<"alpacakit-supervisor-v1">;
33
+ protocolVersion: z.ZodLiteral<"alpacakit-supervisor-v2">;
34
34
  platform: z.ZodEnum<{
35
35
  darwin: "darwin";
36
36
  linux: "linux";
@@ -60,7 +60,7 @@ export declare const controlledProcessRecordSchema: z.ZodReadonly<z.ZodObject<{
60
60
  }, z.core.$strip>>;
61
61
  export declare const signedControlledProcessRecordSchema: z.ZodReadonly<z.ZodObject<{
62
62
  record: z.ZodReadonly<z.ZodObject<{
63
- protocolVersion: z.ZodLiteral<"alpacakit-supervisor-v1">;
63
+ protocolVersion: z.ZodLiteral<"alpacakit-supervisor-v2">;
64
64
  platform: z.ZodEnum<{
65
65
  darwin: "darwin";
66
66
  linux: "linux";
@@ -5,7 +5,7 @@ import { SUPERVISOR_CONVERGENCE_REASON } from "./supervisor-values.js";
5
5
  import { CONTROLLED_PROCESS_PLATFORM, CONTROLLED_PROCESS_PROTOCOL_VERSION, CONTROLLED_PROCESS_STATE, SUPERVISOR_AUTHENTICATION_FRAME_KIND, } from "./values.js";
6
6
  const LOWER_HEX_16_BYTE_PATTERN = /^[0-9a-f]{32}$/u;
7
7
  const LOWER_HEX_32_BYTE_PATTERN = /^[0-9a-f]{64}$/u;
8
- const PROCESS_START_TOKEN_PATTERN = /^alpacakit-supervisor-v1:(?:darwin|linux):[0-9a-f]{32}:[0-9a-f]{32}:[0-9a-f]{32}:[0-9a-f]{32}:[0-9a-f]{64}$/u;
8
+ const PROCESS_START_TOKEN_PATTERN = /^alpacakit-supervisor-v2:(?:darwin|linux):[0-9a-f]{32}:[0-9a-f]{32}:[0-9a-f]{32}:[0-9a-f]{32}:[0-9a-f]{64}$/u;
9
9
  const lowerHex16ByteSchema = z.string().regex(LOWER_HEX_16_BYTE_PATTERN);
10
10
  export const lowerHex32ByteSchema = z.string().regex(LOWER_HEX_32_BYTE_PATTERN);
11
11
  export const controlledProcessPlatformSchema = stringValueMapSchema(CONTROLLED_PROCESS_PLATFORM);
@@ -1 +1 @@
1
- {"version":3,"file":"shim-runtime.d.ts","sourceRoot":"","sources":["../../../src/internal/controlled-process/shim-runtime.ts"],"names":[],"mappings":"AAeA,wBAAsB,wBAAwB,IAAI,OAAO,CAAC,IAAI,CAAC,CAgC9D"}
1
+ {"version":3,"file":"shim-runtime.d.ts","sourceRoot":"","sources":["../../../src/internal/controlled-process/shim-runtime.ts"],"names":[],"mappings":"AAuBA,wBAAsB,wBAAwB,IAAI,OAAO,CAAC,IAAI,CAAC,CAiF9D"}
@@ -1,15 +1,19 @@
1
1
  import { spawn } from "node:child_process";
2
+ import { CONTROLLED_PROCESS_LAUNCH_FAILURE_CODE } from "../../core/error.js";
2
3
  import { readableFd, writableFd } from "./child-fd.js";
3
4
  import { readFramedRecords, readRequiredFrame, writeFramedRecord, } from "./framed-transport.js";
5
+ import { ControlledProcessLaunchError, launchFailure, transferWorkerInput, } from "./input-transport.js";
4
6
  import { shimAckSchema, shimBootstrapSchema } from "./supervisor-schema.js";
5
7
  import { SHIM_FRAME_KIND } from "./supervisor-values.js";
6
8
  const SHIM_CONTROL_FD = 3;
7
9
  const SHIM_STATUS_FD = 4;
10
+ const SHIM_INPUT_FD = 5;
8
11
  const SPAWN_FAILURE_EXIT_CODE = 127;
9
12
  const KEEPALIVE_INTERVAL_MS = 60_000;
10
13
  export async function runControlledProcessShim() {
11
14
  const control = readableFd(SHIM_CONTROL_FD);
12
15
  const status = writableFd(SHIM_STATUS_FD);
16
+ const input = readableFd(SHIM_INPUT_FD);
13
17
  const frames = readFramedRecords(control)[Symbol.asyncIterator]();
14
18
  const bootstrap = shimBootstrapSchema.parse(await readRequiredFrame(frames));
15
19
  try {
@@ -18,7 +22,12 @@ export async function runControlledProcessShim() {
18
22
  catch {
19
23
  return;
20
24
  }
21
- process.on("SIGTERM", () => { });
25
+ let exitFailedLaunchOnSigterm = false;
26
+ process.on("SIGTERM", () => {
27
+ if (exitFailedLaunchOnSigterm) {
28
+ process.exit(0);
29
+ }
30
+ });
22
31
  const worker = spawn(bootstrap.worker.command, [...bootstrap.worker.args], {
23
32
  cwd: bootstrap.worker.cwd,
24
33
  env: bootstrap.worker.env,
@@ -28,10 +37,34 @@ export async function runControlledProcessShim() {
28
37
  });
29
38
  const workerExit = waitForWorkerExit(worker);
30
39
  worker.stdin.on("error", () => { });
31
- if (bootstrap.worker.stdin !== null) {
32
- worker.stdin.write(bootstrap.worker.stdin);
40
+ const delivery = transferWorkerInput({
41
+ readable: input,
42
+ writable: worker.stdin,
43
+ manifest: bootstrap.input,
44
+ stage: "shim_to_worker",
45
+ timeoutMs: bootstrap.inputTimeoutMs,
46
+ });
47
+ void delivery.catch(() => undefined);
48
+ const launch = await Promise.race([
49
+ delivery.then(() => ({ kind: "delivered" }), (error) => ({ kind: "failed", error })),
50
+ workerExit.then((exit) => ({ kind: "exited", exit })),
51
+ ]);
52
+ if (launch.kind === "exited") {
53
+ const failure = launchFailure(CONTROLLED_PROCESS_LAUNCH_FAILURE_CODE.workerExited, "shim_to_worker", bootstrap.input.kind === "stream" ? bootstrap.input.byteLength : 0, null, `Worker exited during input delivery with code ${launch.exit.code ?? "null"}.`);
54
+ exitFailedLaunchOnSigterm = true;
55
+ await reportLaunchFailure(status, failure);
56
+ setInterval(() => { }, KEEPALIVE_INTERVAL_MS);
57
+ return;
58
+ }
59
+ if (launch.kind === "failed") {
60
+ const { error } = launch;
61
+ exitFailedLaunchOnSigterm = true;
62
+ await reportLaunchFailure(status, error instanceof ControlledProcessLaunchError
63
+ ? error
64
+ : launchFailure(CONTROLLED_PROCESS_LAUNCH_FAILURE_CODE.inputWriteFailed, "shim_to_worker", bootstrap.input.kind === "stream" ? bootstrap.input.byteLength : 0, null, "Worker stdin delivery failed.", error));
65
+ setInterval(() => { }, KEEPALIVE_INTERVAL_MS);
66
+ return;
33
67
  }
34
- worker.stdin.end();
35
68
  await writeFramedRecord(status, { kind: SHIM_FRAME_KIND.running });
36
69
  const exit = await workerExit;
37
70
  await writeFramedRecord(status, {
@@ -41,6 +74,12 @@ export async function runControlledProcessShim() {
41
74
  });
42
75
  setInterval(() => { }, KEEPALIVE_INTERVAL_MS);
43
76
  }
77
+ async function reportLaunchFailure(status, error) {
78
+ await writeFramedRecord(status, {
79
+ kind: SHIM_FRAME_KIND.launchFailed,
80
+ failure: error.failure,
81
+ });
82
+ }
44
83
  function waitForWorkerExit(worker) {
45
84
  return new Promise((resolve) => {
46
85
  let spawnFailed = false;
@@ -1 +1 @@
1
- {"version":3,"file":"supervisor-coordinator.d.ts","sourceRoot":"","sources":["../../../src/internal/controlled-process/supervisor-coordinator.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"supervisor-coordinator.d.ts","sourceRoot":"","sources":["../../../src/internal/controlled-process/supervisor-coordinator.ts"],"names":[],"mappings":"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"}
@@ -65,7 +65,8 @@ export class SupervisorCoordinator {
65
65
  return;
66
66
  }
67
67
  this.workerExit = workerExit;
68
- if (this.record.state === CONTROLLED_PROCESS_STATE.running &&
68
+ if ((this.record.state === CONTROLLED_PROCESS_STATE.running ||
69
+ this.record.state === CONTROLLED_PROCESS_STATE.acked) &&
69
70
  !this.groupAbsentObserved &&
70
71
  this.unkillableReason === null) {
71
72
  await this.beginTermination();
@@ -108,7 +109,8 @@ export class SupervisorCoordinator {
108
109
  return this.enqueueResult(async () => {
109
110
  this.terminationRequested = true;
110
111
  this.terminationConvergenceReason ??= convergenceReason;
111
- if (this.record.state === CONTROLLED_PROCESS_STATE.running &&
112
+ if ((this.record.state === CONTROLLED_PROCESS_STATE.running ||
113
+ this.record.state === CONTROLLED_PROCESS_STATE.acked) &&
112
114
  !this.groupAbsentObserved &&
113
115
  this.unkillableReason === null) {
114
116
  await this.beginTermination();
@@ -1,5 +1,6 @@
1
1
  import type { ValueOf } from "@alpacakit/core";
2
2
  import type { ChildProcessIdentity, ChildProcessTerminationResult } from "../../core/controlled-process.js";
3
+ import type { CONTROLLED_PROCESS_LAUNCH_FAILURE_CODE, CONTROLLED_PROCESS_LAUNCH_FAILURE_RETRYABILITY } from "../../core/error.js";
3
4
  import type { ExecExit } from "../../core/ports.js";
4
5
  import type { OUTPUT_CHANNEL_KIND, PROCESS_PROBE_KIND, PROCESS_SIGNAL_RESULT_KIND, SHIM_FRAME_KIND, SUPERVISOR_BOOTSTRAP_FRAME_KIND, SUPERVISOR_CONVERGENCE_REASON, SUPERVISOR_REQUEST_KIND, SUPERVISOR_RESPONSE_KIND } from "./supervisor-values.js";
5
6
  export type SupervisorWorkerOptions = {
@@ -9,7 +10,21 @@ export type SupervisorWorkerOptions = {
9
10
  readonly env: {
10
11
  readonly [key: string]: string;
11
12
  };
12
- readonly stdin: string | null;
13
+ };
14
+ export type WorkerInputManifest = {
15
+ readonly kind: "none";
16
+ } | {
17
+ readonly kind: "stream";
18
+ readonly byteLength: number;
19
+ readonly sha256: string;
20
+ };
21
+ export type ControlledProcessLaunchFailure = {
22
+ readonly code: ValueOf<typeof CONTROLLED_PROCESS_LAUNCH_FAILURE_CODE>;
23
+ readonly retryability: ValueOf<typeof CONTROLLED_PROCESS_LAUNCH_FAILURE_RETRYABILITY>;
24
+ readonly stage: "host_to_supervisor" | "supervisor_to_shim" | "shim_to_worker" | "control_protocol";
25
+ readonly expectedBytes: number | null;
26
+ readonly actualBytes: number | null;
27
+ readonly message: string;
13
28
  };
14
29
  export type SupervisorTimingOptions = {
15
30
  readonly termGraceMs: number;
@@ -23,6 +38,7 @@ export type SupervisorBootstrap = {
23
38
  readonly runtimeDirectory: string;
24
39
  readonly shimEntryPath: string;
25
40
  readonly worker: SupervisorWorkerOptions;
41
+ readonly input: WorkerInputManifest;
26
42
  readonly timing: SupervisorTimingOptions;
27
43
  };
28
44
  export type SupervisorHostAck = {
@@ -34,11 +50,13 @@ export type SupervisorIdentityFrame = {
34
50
  };
35
51
  export type SupervisorLaunchFailedFrame = {
36
52
  readonly kind: typeof SUPERVISOR_BOOTSTRAP_FRAME_KIND.launchFailed;
37
- readonly reason: string;
53
+ readonly failure: ControlledProcessLaunchFailure;
38
54
  };
39
55
  export type ShimBootstrap = {
40
56
  readonly kind: typeof SHIM_FRAME_KIND.bootstrap;
41
57
  readonly worker: SupervisorWorkerOptions;
58
+ readonly input: WorkerInputManifest;
59
+ readonly inputTimeoutMs: number;
42
60
  };
43
61
  export type ShimAck = {
44
62
  readonly kind: typeof SHIM_FRAME_KIND.ack;
@@ -46,6 +64,10 @@ export type ShimAck = {
46
64
  export type ShimRunning = {
47
65
  readonly kind: typeof SHIM_FRAME_KIND.running;
48
66
  };
67
+ export type ShimLaunchFailed = {
68
+ readonly kind: typeof SHIM_FRAME_KIND.launchFailed;
69
+ readonly failure: ControlledProcessLaunchFailure;
70
+ };
49
71
  export type WorkerExit = {
50
72
  readonly kind: typeof SHIM_FRAME_KIND.workerExit;
51
73
  readonly code: number | null;