@opengeni/runtime 2.5.3-canary.0 → 2.5.3-canary.2

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.
@@ -15993,6 +15993,9 @@ function agentErrorToControlError(err, controlRequestId = null) {
15993
15993
  }
15994
15994
  }
15995
15995
  function payloadTooLargeMessage(detail) {
15996
+ if (detail.direction === "request") {
15997
+ return "The request exceeds the machine link's per-message size limit and was not sent. The machine is not offline. Use a supported bounded transfer for large file content.";
15998
+ }
15996
15999
  const encoded = detail.encoded_bytes;
15997
16000
  const max = detail.max_payload;
15998
16001
  const sizes = encoded && max ? `The result was ${encoded} bytes, over the machine link's ${max}-byte per-message limit. ` : "The result was larger than the machine link can deliver in a single message. ";
@@ -16105,6 +16108,18 @@ var NatsControlRpc = class {
16105
16108
  } catch (err) {
16106
16109
  const denied = natsAuthorizationFailure(err);
16107
16110
  if (denied) throw denied;
16111
+ if (typeof err === "object" && err !== null && "code" in err && err.code === "MAX_PAYLOAD_EXCEEDED") {
16112
+ return {
16113
+ requestId: req.requestId,
16114
+ error: {
16115
+ code: ErrorCode.ERROR_CODE_PAYLOAD_TOO_LARGE,
16116
+ message: "outbound control request exceeds the transport payload limit",
16117
+ retryable: false,
16118
+ detail: { direction: "request", encoded_bytes: String(payload.byteLength) }
16119
+ },
16120
+ result: void 0
16121
+ };
16122
+ }
16108
16123
  if (isNoRespondersError(err)) {
16109
16124
  return offlineControlResponse(req.requestId, true);
16110
16125
  }
@@ -16185,6 +16200,15 @@ function assemble(error, f) {
16185
16200
  function renderSelfhostedFault(error) {
16186
16201
  const detail = error.detail;
16187
16202
  if (error.payloadTooLarge || error.code === ErrorCode2.ERROR_CODE_PAYLOAD_TOO_LARGE) {
16203
+ if (detail.direction === "request") {
16204
+ return assemble(error, {
16205
+ headline: "the request was too large to send",
16206
+ happened: "the request was not sent because it exceeded the per-message size limit",
16207
+ layer: "the machine link's outbound request size limit, not machine availability",
16208
+ preserved: "the rejected request did not execute on the machine",
16209
+ tryNext: "use a supported bounded transfer; retrying the unchanged request will not help"
16210
+ });
16211
+ }
16188
16212
  if (detail.failure_code === "OP_OVERFLOW") {
16189
16213
  const retained = detail.retained_bytes ? `after retaining ${detail.retained_bytes} bytes of output` : "when its output exceeded what the machine can retain for delivery";
16190
16214
  return assemble(error, {
@@ -25876,6 +25900,120 @@ import {
25876
25900
  } from "@opengeni/agent-proto";
25877
25901
  import { DESKTOP_STREAM_PORT as DESKTOP_STREAM_PORT4 } from "@opengeni/contracts";
25878
25902
 
25903
+ // src/sandbox/selfhosted/file-transfer.ts
25904
+ import { blake3 } from "@noble/hashes/blake3";
25905
+ import { bytesToHex } from "@noble/hashes/utils";
25906
+ import { OpState } from "@opengeni/agent-proto";
25907
+ var SELFHOSTED_FILE_CHUNK_BYTES = 256 * 1024;
25908
+ function fileContentDigest(content) {
25909
+ return bytesToHex(blake3(content));
25910
+ }
25911
+ var FileTransferOutcomeError = class extends Error {
25912
+ constructor(operationId, phase, cause, observationError) {
25913
+ const detail = cause instanceof Error ? cause.message : "unknown failure";
25914
+ const observation = observationError instanceof Error ? ` Outcome check: ${observationError.message}` : "";
25915
+ super(
25916
+ `File transfer ${operationId} ${phase} failed: ${detail}.${observation} No mutation was replayed; inspect the destination before another edit.`,
25917
+ { cause }
25918
+ );
25919
+ this.operationId = operationId;
25920
+ this.phase = phase;
25921
+ this.observationError = observationError;
25922
+ this.name = "FileTransferOutcomeError";
25923
+ }
25924
+ retryable = false;
25925
+ };
25926
+ async function transferEditorFile(input) {
25927
+ const opId = `fsw-${crypto.randomUUID()}`;
25928
+ const digest = fileContentDigest(input.content);
25929
+ const checked = (reply) => {
25930
+ if (reply.error) throw agentErrorToControlError(reply.error, reply.requestId);
25931
+ if (!reply.result) throw new Error("The machine omitted the file-transfer result.");
25932
+ return reply.result;
25933
+ };
25934
+ const send = async (requestId2, op) => {
25935
+ const reply = await input.request(requestId2, op);
25936
+ if (reply.requestId !== requestId2)
25937
+ throw new Error("The machine returned a mismatched file-transfer response identity.");
25938
+ return checked(reply);
25939
+ };
25940
+ const isVerified = (observed) => !(observed.$case !== "opStatus" || observed.opStatus.opId !== opId || observed.opStatus.state !== OpState.OP_STATE_COMPLETE || observed.opStatus.exit?.exitCode !== 0 || observed.opStatus.exit.cancelled || observed.opStatus.exit.timedOut || observed.opStatus.exit.failureCode || observed.opStatus.exit.digests.content !== digest || observed.opStatus.exit.totals.content !== String(input.content.byteLength));
25941
+ const verifyOutcome = async (cancelRunning = false) => {
25942
+ const observed = await send(crypto.randomUUID(), { $case: "opQuery", opQuery: { opId } });
25943
+ if (isVerified(observed)) return;
25944
+ if (cancelRunning && observed.$case === "opStatus" && observed.opStatus.opId === opId && observed.opStatus.state === OpState.OP_STATE_RUNNING) {
25945
+ const cancelled = await send(crypto.randomUUID(), { $case: "opCancel", opCancel: { opId } });
25946
+ if (isVerified(cancelled)) return;
25947
+ if (cancelled.$case === "opStatus" && cancelled.opStatus.opId === opId && cancelled.opStatus.state === OpState.OP_STATE_COMPLETE && cancelled.opStatus.exit?.cancelled) {
25948
+ throw new Error("Cancellation of the abandoned transfer's private staging was verified.");
25949
+ }
25950
+ }
25951
+ throw new Error(
25952
+ "The file-transfer outcome is not verified; the operation was not replayed. Inspect the destination before another edit."
25953
+ );
25954
+ };
25955
+ let phase = "begin";
25956
+ try {
25957
+ const begun = await send(opId, {
25958
+ $case: "opStart",
25959
+ opStart: {
25960
+ op: {
25961
+ $case: "fsWrite",
25962
+ fsWrite: {
25963
+ path: input.path,
25964
+ createParents: true,
25965
+ mode: 0,
25966
+ expectedBaseDigest: input.baseContent === void 0 ? "" : fileContentDigest(input.baseContent),
25967
+ expectedAbsent: input.baseContent === void 0,
25968
+ contentDigest: digest,
25969
+ contentSize: String(input.content.byteLength)
25970
+ }
25971
+ },
25972
+ windowBytes: "0",
25973
+ deadlineMs: "0",
25974
+ originId: ""
25975
+ }
25976
+ });
25977
+ if (begun.$case !== "opStart" || !begun.opStart.accepted || begun.opStart.status?.opId !== opId) {
25978
+ throw new Error("The machine did not accept the exact file-transfer operation.");
25979
+ }
25980
+ phase = "upload";
25981
+ let offset = 0;
25982
+ let seq = 0;
25983
+ do {
25984
+ const end = Math.min(input.content.byteLength, offset + SELFHOSTED_FILE_CHUNK_BYTES);
25985
+ const reply = await send(crypto.randomUUID(), {
25986
+ $case: "writeChunk",
25987
+ writeChunk: {
25988
+ opId,
25989
+ seq: String(seq),
25990
+ offset: String(offset),
25991
+ bytes: input.content.subarray(offset, end),
25992
+ last: end === input.content.byteLength
25993
+ }
25994
+ });
25995
+ if (reply.$case !== "writeChunk" || reply.writeChunk.seq !== String(seq)) {
25996
+ throw new Error(
25997
+ "The machine returned a mismatched file-transfer acknowledgment; no chunk was replayed."
25998
+ );
25999
+ }
26000
+ offset = end;
26001
+ seq += 1;
26002
+ } while (offset < input.content.byteLength);
26003
+ phase = "verify";
26004
+ await verifyOutcome();
26005
+ } catch (error) {
26006
+ if (phase === "verify") throw new FileTransferOutcomeError(opId, phase, error);
26007
+ try {
26008
+ await verifyOutcome(true);
26009
+ return { recovered: true };
26010
+ } catch (observationError) {
26011
+ throw new FileTransferOutcomeError(opId, phase, error, observationError);
26012
+ }
26013
+ }
26014
+ return { recovered: false };
26015
+ }
26016
+
25879
26017
  // src/sandbox/selfhosted/retry-policy.ts
25880
26018
  var SELFHOSTED_IDEMPOTENT_READONLY_OPS = /* @__PURE__ */ new Set([
25881
26019
  "ping",
@@ -25929,15 +26067,15 @@ var defaultSelfhostedRetryClock = {
25929
26067
  };
25930
26068
 
25931
26069
  // src/sandbox/selfhosted/op-stream.ts
25932
- import { blake3 } from "@noble/hashes/blake3";
25933
- import { bytesToHex } from "@noble/hashes/utils";
26070
+ import { blake3 as blake32 } from "@noble/hashes/blake3";
26071
+ import { bytesToHex as bytesToHex2 } from "@noble/hashes/utils";
25934
26072
  import {
25935
26073
  ErrorCode as ErrorCode3,
25936
26074
  OpAck,
25937
26075
  OpChannel,
25938
26076
  OpFrame,
25939
26077
  OpLostReason,
25940
- OpState
26078
+ OpState as OpState2
25941
26079
  } from "@opengeni/agent-proto";
25942
26080
 
25943
26081
  // src/sandbox/selfhosted/op-transport.ts
@@ -26260,7 +26398,7 @@ var OpConsumer = class {
26260
26398
  };
26261
26399
  outputFrames = [];
26262
26400
  outputDecoders = { stdout: new TextDecoder(), stderr: new TextDecoder() };
26263
- hashes = { stdout: blake3.create(), stderr: blake3.create() };
26401
+ hashes = { stdout: blake32.create(), stderr: blake32.create() };
26264
26402
  totals = { stdout: 0n, stderr: 0n };
26265
26403
  captureOnly = false;
26266
26404
  receivedPayloadBytes = 0n;
@@ -26429,7 +26567,7 @@ var OpConsumer = class {
26429
26567
  if (result.$case !== "opStatus") {
26430
26568
  throw protocolError(`op-stream cancel: unexpected result ${result.$case}`);
26431
26569
  }
26432
- if (result.opStatus.state === OpState.OP_STATE_LOST) {
26570
+ if (result.opStatus.state === OpState2.OP_STATE_LOST) {
26433
26571
  throw lostToControlError(result.opStatus);
26434
26572
  }
26435
26573
  await this.attach(0);
@@ -26498,7 +26636,7 @@ var OpConsumer = class {
26498
26636
  if (!result.opStart.accepted) {
26499
26637
  throw this.refusedStart(status);
26500
26638
  }
26501
- if (status?.state === OpState.OP_STATE_LOST) {
26639
+ if (status?.state === OpState2.OP_STATE_LOST) {
26502
26640
  throw lostToControlError(status);
26503
26641
  }
26504
26642
  return drainingRetries + blipRetries;
@@ -26541,7 +26679,7 @@ var OpConsumer = class {
26541
26679
  detail: { cancelled: "true" }
26542
26680
  });
26543
26681
  }
26544
- if (status?.state === OpState.OP_STATE_LOST) {
26682
+ if (status?.state === OpState2.OP_STATE_LOST) {
26545
26683
  return lostToControlError(status);
26546
26684
  }
26547
26685
  return protocolError("op-stream start: the runner refused the op without a typed reason");
@@ -26589,7 +26727,7 @@ var OpConsumer = class {
26589
26727
  if (result.$case !== "opStatus") {
26590
26728
  throw protocolError(`op-stream attach: unexpected result ${result.$case}`);
26591
26729
  }
26592
- if (result.opStatus.state === OpState.OP_STATE_LOST) {
26730
+ if (result.opStatus.state === OpState2.OP_STATE_LOST) {
26593
26731
  throw lostToControlError(result.opStatus);
26594
26732
  }
26595
26733
  return result.opStatus;
@@ -26779,7 +26917,7 @@ var OpConsumer = class {
26779
26917
  throw protocolError(`op-stream query: unexpected result ${result.$case}`);
26780
26918
  }
26781
26919
  const status = result.opStatus;
26782
- if (status.state === OpState.OP_STATE_LOST) {
26920
+ if (status.state === OpState2.OP_STATE_LOST) {
26783
26921
  reject(lostToControlError(status));
26784
26922
  return;
26785
26923
  }
@@ -26819,8 +26957,8 @@ var OpConsumer = class {
26819
26957
  }
26820
26958
  const declaredDigest = exit.digests[channel];
26821
26959
  if (declaredDigest) {
26822
- const digest = bytesToHex(
26823
- this.captureOnly ? this.hashes[channel].clone().digest() : blake3(bytes)
26960
+ const digest = bytesToHex2(
26961
+ this.captureOnly ? this.hashes[channel].clone().digest() : blake32(bytes)
26824
26962
  );
26825
26963
  if (digest !== declaredDigest) {
26826
26964
  throw protocolError(
@@ -27000,6 +27138,7 @@ var SelfhostedSession = class {
27000
27138
  resourcePolicy;
27001
27139
  resourcePolicySupported;
27002
27140
  operationCpuQuotaSupported;
27141
+ transactionalFsWriteSupported;
27003
27142
  defaultOpStream;
27004
27143
  connectionInstanceId;
27005
27144
  resolveOperationAdmission;
@@ -27059,6 +27198,7 @@ var SelfhostedSession = class {
27059
27198
  this.resourcePolicy = normalizeOperationResourcePolicy(deps.operationResourcePolicy);
27060
27199
  this.resourcePolicySupported = deps.operationResourcePolicySupported === true;
27061
27200
  this.operationCpuQuotaSupported = deps.operationCpuQuotaSupported === true;
27201
+ this.transactionalFsWriteSupported = deps.transactionalFsWriteSupported === true;
27062
27202
  this.defaultOpStream = deps.opStream;
27063
27203
  this.connectionInstanceId = deps.connectionInstanceId;
27064
27204
  this.resolveOperationAdmission = deps.resolveOperationAdmission;
@@ -27070,7 +27210,8 @@ var SelfhostedSession = class {
27070
27210
  connectionInstanceId: deps.connectionInstanceId,
27071
27211
  subject: this.subject,
27072
27212
  resourcePolicy: this.resourcePolicy,
27073
- opStream: deps.opStream
27213
+ opStream: deps.opStream,
27214
+ transactionalFsWriteSupported: this.transactionalFsWriteSupported
27074
27215
  }) : void 0;
27075
27216
  this.state = {
27076
27217
  agentId: deps.agentId,
@@ -27130,7 +27271,8 @@ var SelfhostedSession = class {
27130
27271
  connectionInstanceId: this.connectionInstanceId,
27131
27272
  subject: this.subject,
27132
27273
  resourcePolicy: commandPolicy ? this.resourcePolicy : void 0,
27133
- opStream: this.defaultOpStream
27274
+ opStream: this.defaultOpStream,
27275
+ transactionalFsWriteSupported: this.transactionalFsWriteSupported
27134
27276
  };
27135
27277
  }
27136
27278
  const resolved = await this.resolveOperationAdmission();
@@ -27163,7 +27305,8 @@ var SelfhostedSession = class {
27163
27305
  resolved.connectionInstanceId
27164
27306
  ),
27165
27307
  resourcePolicy: commandPolicy ? resourcePolicy : void 0,
27166
- opStream: resolved.opStream
27308
+ opStream: resolved.opStream,
27309
+ transactionalFsWriteSupported: resolved.transactionalFsWriteSupported === true
27167
27310
  };
27168
27311
  }
27169
27312
  async admitCommand() {
@@ -27306,7 +27449,7 @@ var SelfhostedSession = class {
27306
27449
  machineId: this.agentId,
27307
27450
  faultClass: selfhostedFaultClass(error),
27308
27451
  // Known only on a PAYLOAD_TOO_LARGE fault (the agent's encoded_bytes detail).
27309
- ...Number.isFinite(encoded) ? { replyBytes: encoded } : {}
27452
+ ...Number.isFinite(encoded) && error.detail.direction !== "request" ? { replyBytes: encoded } : {}
27310
27453
  });
27311
27454
  if (error.draining && drainingRetries > 0) {
27312
27455
  throw drainingExhaustedError(error, drainingRetries);
@@ -27671,8 +27814,145 @@ var SelfhostedSession = class {
27671
27814
  }
27672
27815
  const pathExists3 = (path) => this.pathExists(path, runAs);
27673
27816
  const readText2 = async (path) => decoder.decode(await this.readFile({ path, ...runAs ? { runAs } : {} }));
27674
- const writeText = async (path, content) => {
27675
- await this.writeFile({ path, content, createParents: true });
27817
+ const writeText = async (path, content, base) => {
27818
+ const bytes = encoder.encode(content);
27819
+ if (bytes.byteLength <= SELFHOSTED_FILE_CHUNK_BYTES) {
27820
+ await this.writeFile({ path, content, createParents: true });
27821
+ return;
27822
+ }
27823
+ const initial = await this.admitOperation(false);
27824
+ if (!initial.transactionalFsWriteSupported) {
27825
+ await this.writeFile({ path, content, createParents: true });
27826
+ return;
27827
+ }
27828
+ if (runAs) {
27829
+ throw new SelfhostedControlError({
27830
+ code: ErrorCode4.ERROR_CODE_UNSUPPORTED,
27831
+ message: "Transactional file editing does not support runAs impersonation; no file was written.",
27832
+ reason: null,
27833
+ retryable: false
27834
+ });
27835
+ }
27836
+ const requestTransfer = async (requestId2, op) => {
27837
+ const startedAt = Date.now();
27838
+ try {
27839
+ const current = await this.admitOperation(false);
27840
+ if (!current.transactionalFsWriteSupported || current.subject !== initial.subject || current.connectionInstanceId !== initial.connectionInstanceId) {
27841
+ throw new Error(
27842
+ "The authorized machine connection changed during the file transfer; the operation was not replayed."
27843
+ );
27844
+ }
27845
+ const response = await this.controlRpc.request(
27846
+ current.subject,
27847
+ {
27848
+ requestId: requestId2,
27849
+ epoch: this.epoch,
27850
+ op,
27851
+ resourcePolicy: void 0
27852
+ },
27853
+ { timeoutMs: this.timeoutMs }
27854
+ );
27855
+ if (response.requestId !== requestId2)
27856
+ throw new Error("The machine returned a mismatched file-transfer response identity.");
27857
+ const error = response.error ? agentErrorToControlError(response.error, requestId2) : void 0;
27858
+ this.emitOp({
27859
+ op: op.$case,
27860
+ outcome: error || !response.result ? "failed" : "ok",
27861
+ healed: false,
27862
+ retries: 0,
27863
+ durationMs: Date.now() - startedAt,
27864
+ machineId: this.agentId,
27865
+ ...error ? { code: error.code, reason: error.reason, faultClass: selfhostedFaultClass(error) } : {}
27866
+ });
27867
+ return response;
27868
+ } catch (error) {
27869
+ this.emitOp({
27870
+ op: op.$case,
27871
+ outcome: "failed",
27872
+ healed: false,
27873
+ retries: 0,
27874
+ durationMs: Date.now() - startedAt,
27875
+ machineId: this.agentId,
27876
+ ...error instanceof SelfhostedControlError ? { code: error.code, reason: error.reason, faultClass: selfhostedFaultClass(error) } : {}
27877
+ });
27878
+ throw error;
27879
+ }
27880
+ };
27881
+ const resolvedBase = typeof base === "function" ? await base() : base;
27882
+ const transferStartedAt = Date.now();
27883
+ try {
27884
+ const result = await transferEditorFile({
27885
+ path: resolveConnectedMachinePath(this.workspaceRoot, path),
27886
+ content: bytes,
27887
+ ...resolvedBase === void 0 ? {} : { baseContent: encoder.encode(resolvedBase) },
27888
+ request: requestTransfer
27889
+ });
27890
+ this.emitOp({
27891
+ op: "fsWrite",
27892
+ outcome: "ok",
27893
+ healed: result.recovered,
27894
+ retries: 0,
27895
+ durationMs: Date.now() - transferStartedAt,
27896
+ machineId: this.agentId
27897
+ });
27898
+ } catch (error) {
27899
+ this.emitOp({
27900
+ op: "fsWrite",
27901
+ outcome: "failed",
27902
+ healed: false,
27903
+ retries: 0,
27904
+ durationMs: Date.now() - transferStartedAt,
27905
+ machineId: this.agentId
27906
+ });
27907
+ throw error;
27908
+ }
27909
+ return async (source, sourceBase) => {
27910
+ try {
27911
+ const sourcePath = resolveConnectedMachinePath(this.workspaceRoot, source);
27912
+ const sourceBytes = [];
27913
+ let offset = 0;
27914
+ let total = Infinity;
27915
+ while (offset < total) {
27916
+ const reply2 = await requestTransfer(crypto.randomUUID(), {
27917
+ $case: "fsRead",
27918
+ fsRead: {
27919
+ path: sourcePath,
27920
+ offset: String(offset),
27921
+ length: String(SELFHOSTED_FILE_CHUNK_BYTES)
27922
+ }
27923
+ });
27924
+ if (reply2.error) throw agentErrorToControlError(reply2.error);
27925
+ if (reply2.result?.$case !== "fsRead")
27926
+ throw new Error("Source verification response missing");
27927
+ const part = reply2.result.fsRead;
27928
+ total = safeWireSize(part.totalSize, "source file size");
27929
+ if (!part.content.length && offset < total)
27930
+ throw new Error("Source verification was incomplete");
27931
+ sourceBytes.push(part.content);
27932
+ offset += part.content.length;
27933
+ }
27934
+ const actual = new Uint8Array(offset);
27935
+ let cursor = 0;
27936
+ for (const chunk of sourceBytes) {
27937
+ actual.set(chunk, cursor);
27938
+ cursor += chunk.length;
27939
+ }
27940
+ if (fileContentDigest(actual) !== fileContentDigest(encoder.encode(sourceBase)))
27941
+ throw new Error("Source changed before move cleanup");
27942
+ const reply = await requestTransfer(crypto.randomUUID(), {
27943
+ $case: "fsRemove",
27944
+ fsRemove: { path: sourcePath, recursive: false }
27945
+ });
27946
+ if (reply.error) throw agentErrorToControlError(reply.error);
27947
+ if (reply.result?.$case !== "fsRemove")
27948
+ throw new Error("Source cleanup response missing");
27949
+ } catch (cause) {
27950
+ throw new Error(
27951
+ "The destination edit was verified, but source cleanup was not verified. The move was not replayed; inspect both paths.",
27952
+ { cause }
27953
+ );
27954
+ }
27955
+ };
27676
27956
  };
27677
27957
  const deletePath = async (path) => {
27678
27958
  const result = await this.call({
@@ -27698,9 +27978,11 @@ var SelfhostedSession = class {
27698
27978
  const current = await readText2(operation.path);
27699
27979
  const next = applyDiff2(current, operation.diff);
27700
27980
  const destination = operation.moveTo ?? operation.path;
27701
- await writeText(destination, next);
27981
+ const destinationBase = destination === operation.path ? current : async () => await pathExists3(destination) ? await readText2(destination) : void 0;
27982
+ const cleanup = await writeText(destination, next, destinationBase);
27702
27983
  if (operation.moveTo && destination !== operation.path) {
27703
- await deletePath(operation.path);
27984
+ if (cleanup) await cleanup(operation.path, current);
27985
+ else await deletePath(operation.path);
27704
27986
  }
27705
27987
  return {};
27706
27988
  },
@@ -27984,6 +28266,7 @@ var SelfhostedSandboxClient = class {
27984
28266
  operationResourcePolicy;
27985
28267
  operationResourcePolicySupported;
27986
28268
  operationCpuQuotaSupported;
28269
+ transactionalFsWriteSupported;
27987
28270
  resolveOperationAdmission;
27988
28271
  adoptBackgroundCommand;
27989
28272
  settleBackgroundCommand;
@@ -28006,6 +28289,7 @@ var SelfhostedSandboxClient = class {
28006
28289
  this.operationResourcePolicy = opts.operationResourcePolicy;
28007
28290
  this.operationResourcePolicySupported = opts.operationResourcePolicySupported;
28008
28291
  this.operationCpuQuotaSupported = opts.operationCpuQuotaSupported;
28292
+ this.transactionalFsWriteSupported = opts.transactionalFsWriteSupported;
28009
28293
  this.resolveOperationAdmission = opts.resolveOperationAdmission;
28010
28294
  this.adoptBackgroundCommand = opts.adoptBackgroundCommand;
28011
28295
  this.settleBackgroundCommand = opts.settleBackgroundCommand;
@@ -28039,6 +28323,7 @@ var SelfhostedSandboxClient = class {
28039
28323
  operationResourcePolicySupported: this.operationResourcePolicySupported
28040
28324
  } : {},
28041
28325
  ...this.operationCpuQuotaSupported !== void 0 ? { operationCpuQuotaSupported: this.operationCpuQuotaSupported } : {},
28326
+ transactionalFsWriteSupported: this.transactionalFsWriteSupported === true,
28042
28327
  ...this.resolveOperationAdmission !== void 0 ? { resolveOperationAdmission: this.resolveOperationAdmission } : {},
28043
28328
  ...this.adoptBackgroundCommand !== void 0 ? { adoptBackgroundCommand: this.adoptBackgroundCommand } : {},
28044
28329
  ...this.settleBackgroundCommand !== void 0 ? { settleBackgroundCommand: this.settleBackgroundCommand } : {},
@@ -28109,6 +28394,7 @@ async function buildSelfhostedBackendSession(deps) {
28109
28394
  operationResourcePolicySupported: deps.operationResourcePolicySupported
28110
28395
  } : {},
28111
28396
  ...deps.operationCpuQuotaSupported !== void 0 ? { operationCpuQuotaSupported: deps.operationCpuQuotaSupported } : {},
28397
+ transactionalFsWriteSupported: deps.transactionalFsWriteSupported === true,
28112
28398
  ...deps.resolveOperationAdmission !== void 0 ? { resolveOperationAdmission: deps.resolveOperationAdmission } : {},
28113
28399
  ...deps.adoptBackgroundCommand !== void 0 ? { adoptBackgroundCommand: deps.adoptBackgroundCommand } : {},
28114
28400
  ...deps.settleBackgroundCommand !== void 0 ? { settleBackgroundCommand: deps.settleBackgroundCommand } : {},
@@ -35006,15 +35292,15 @@ function concat(a, b) {
35006
35292
  }
35007
35293
 
35008
35294
  // src/sandbox/selfhosted/op-testing.ts
35009
- import { blake3 as blake32 } from "@noble/hashes/blake3";
35010
- import { bytesToHex as bytesToHex2 } from "@noble/hashes/utils";
35295
+ import { blake3 as blake33 } from "@noble/hashes/blake3";
35296
+ import { bytesToHex as bytesToHex3 } from "@noble/hashes/utils";
35011
35297
  import {
35012
35298
  ErrorCode as ErrorCode6,
35013
35299
  OpAck as OpAck2,
35014
35300
  OpChannel as OpChannel2,
35015
35301
  OpFrame as OpFrame2,
35016
35302
  OpLostReason as OpLostReason2,
35017
- OpState as OpState2
35303
+ OpState as OpState3
35018
35304
  } from "@opengeni/agent-proto";
35019
35305
  var InMemoryOpStreamTransport = class {
35020
35306
  available = true;
@@ -35307,8 +35593,9 @@ var FakeOpRunner = class {
35307
35593
  const complete = !run2.script.live || run2.liveEmitted;
35308
35594
  return {
35309
35595
  opId,
35310
- state: complete ? OpState2.OP_STATE_COMPLETE : OpState2.OP_STATE_RUNNING,
35596
+ state: complete ? OpState3.OP_STATE_COMPLETE : OpState3.OP_STATE_RUNNING,
35311
35597
  nextSeq: complete ? (run2.exitSeq + 1n).toString() : "1",
35598
+ writeOffset: "0",
35312
35599
  exit: complete ? run2.exit : void 0,
35313
35600
  lostReason: OpLostReason2.OP_LOST_REASON_UNSPECIFIED
35314
35601
  };
@@ -35342,7 +35629,7 @@ var FakeOpRunner = class {
35342
35629
  const totals = {};
35343
35630
  for (const channel of ["stdout", "stderr"]) {
35344
35631
  const joined = concat2(channelBytes[channel]);
35345
- digests[channel] = bytesToHex2(blake32(joined));
35632
+ digests[channel] = bytesToHex3(blake33(joined));
35346
35633
  totals[channel] = String(joined.byteLength);
35347
35634
  }
35348
35635
  const exit = {
@@ -35448,7 +35735,8 @@ function statusOnly(requestId2, status) {
35448
35735
  function lostStatus(opId) {
35449
35736
  return {
35450
35737
  opId,
35451
- state: OpState2.OP_STATE_LOST,
35738
+ state: OpState3.OP_STATE_LOST,
35739
+ writeOffset: "0",
35452
35740
  nextSeq: "0",
35453
35741
  exit: void 0,
35454
35742
  lostReason: OpLostReason2.OP_LOST_REASON_EVICTED
@@ -35457,7 +35745,8 @@ function lostStatus(opId) {
35457
35745
  function cancelledStatus(opId) {
35458
35746
  return {
35459
35747
  opId,
35460
- state: OpState2.OP_STATE_COMPLETE,
35748
+ state: OpState3.OP_STATE_COMPLETE,
35749
+ writeOffset: "0",
35461
35750
  nextSeq: "1",
35462
35751
  exit: {
35463
35752
  exitCode: -1,
@@ -35577,6 +35866,7 @@ function makeActiveBackendResolver(deps) {
35577
35866
  operationResourcePolicy: connection.operationResourcePolicy,
35578
35867
  operationResourcePolicySupported: connection.operationResourcePolicySupported,
35579
35868
  operationCpuQuotaSupported: connection.operationCpuQuotaSupported,
35869
+ transactionalFsWriteSupported: connection.transactionalFsWriteSupported === true,
35580
35870
  // The routing proxy caches this session by sandbox+epoch, but command
35581
35871
  // policy and runner authority are mutable. Re-read one coherent DB
35582
35872
  // snapshot only when a new exec/Git is admitted.
@@ -37003,4 +37293,4 @@ export {
37003
37293
  collectSandboxEnvironment2 as collectSandboxEnvironment,
37004
37294
  parseExposedPorts2 as parseExposedPorts
37005
37295
  };
37006
- //# sourceMappingURL=chunk-VVEGJPDR.js.map
37296
+ //# sourceMappingURL=chunk-46BFUGFL.js.map