@tangle-network/agent-app 0.44.22 → 0.44.24

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.
@@ -93,7 +93,7 @@ import {
93
93
  flattenHistory,
94
94
  readSandboxBinaryBytes,
95
95
  statSandboxFileSize
96
- } from "../chunk-2ZSSOYXP.js";
96
+ } from "../chunk-ALGZJBW2.js";
97
97
  import "../chunk-LWSJK546.js";
98
98
  import "../chunk-CQZSAR77.js";
99
99
  import "../chunk-ICOHEZK6.js";
@@ -722,6 +722,21 @@ var SandboxRuntimeAuthRefreshError = class extends Error {
722
722
  this.name = "SandboxRuntimeAuthRefreshError";
723
723
  }
724
724
  };
725
+ var SandboxRecoveryFailedError = class extends Error {
726
+ boxKey;
727
+ stage;
728
+ phase;
729
+ constructor(stage, boxKey, phase, detail, cause) {
730
+ super(
731
+ `${stage} sandbox ${boxKey} failed liveness recovery at ${phase}: ${detail}. The workspace is preserved; pass forceNew to replace the box.`,
732
+ { cause }
733
+ );
734
+ this.name = "SandboxRecoveryFailedError";
735
+ this.boxKey = boxKey;
736
+ this.stage = stage;
737
+ this.phase = phase;
738
+ }
739
+ };
725
740
  function fileApiTarget(mount) {
726
741
  if (mount.resource.kind !== "inline") return null;
727
742
  let rel;
@@ -1081,6 +1096,39 @@ async function resumeStoppedBox(box, timeoutMs, onProgress) {
1081
1096
  return fail(err);
1082
1097
  }
1083
1098
  }
1099
+ async function recoverUnresponsiveBox(client, box, harness, probe, stage, name, resumeTimeout, onProgress) {
1100
+ try {
1101
+ await box.stop();
1102
+ } catch (err) {
1103
+ throw new SandboxRecoveryFailedError(
1104
+ stage,
1105
+ name,
1106
+ "stop",
1107
+ "the platform could not stop the box for a state-preserving restart",
1108
+ err
1109
+ );
1110
+ }
1111
+ const resumed = await resumeStoppedBox(box, resumeTimeout, onProgress);
1112
+ if (!resumed.succeeded) {
1113
+ throw new SandboxRecoveryFailedError(
1114
+ stage,
1115
+ name,
1116
+ "resume",
1117
+ "the box did not reach running after a state-preserving restart",
1118
+ resumed.error
1119
+ );
1120
+ }
1121
+ const recovered = await refreshRuntimeConnection(client, resumed.value);
1122
+ if (!await isReusableBox(recovered, harness, probe)) {
1123
+ throw new SandboxRecoveryFailedError(
1124
+ stage,
1125
+ name,
1126
+ "probe",
1127
+ "the box is still unresponsive after a state-preserving restart"
1128
+ );
1129
+ }
1130
+ return recovered;
1131
+ }
1084
1132
  async function resolveWorkspaceSandboxClient(shell, workspaceId, userId) {
1085
1133
  const scope = { workspaceId, ...userId ? { userId } : {} };
1086
1134
  const creds = await shell.credentials(scope);
@@ -1100,6 +1148,29 @@ async function peekWorkspaceSandbox(shell, options) {
1100
1148
  if (match.status !== "running") return { status: "not-running", state: match.status, box: match };
1101
1149
  return { status: "running", box: match };
1102
1150
  }
1151
+ async function finalizeExistingBox(shell, client, box, stage, name, workspaceId, userId, harness, scope) {
1152
+ const written = await materializeDeferredFilesForExistingBox(
1153
+ shell,
1154
+ client,
1155
+ box,
1156
+ stage,
1157
+ name,
1158
+ workspaceId,
1159
+ userId,
1160
+ harness
1161
+ );
1162
+ if (!written.succeeded) {
1163
+ throw deferredProfileWriteFailed(stage, name, written.error);
1164
+ }
1165
+ const finalBox = written.value;
1166
+ if (shell.bootstrap) {
1167
+ const boot = await shell.bootstrap(finalBox, scope);
1168
+ if (!boot.succeeded) {
1169
+ throw new Error(`bootstrap failed on ${stage} box ${name}`, { cause: boot.error });
1170
+ }
1171
+ }
1172
+ return finalBox;
1173
+ }
1103
1174
  async function ensureWorkspaceSandbox(shell, options) {
1104
1175
  const { workspaceId, userId, harness, forceNew, onProgress, billingOwnerId } = options;
1105
1176
  const resolved = await resolveWorkspaceSandboxClient(shell, workspaceId, userId);
@@ -1119,40 +1190,24 @@ async function ensureWorkspaceSandbox(shell, options) {
1119
1190
  } else if (found.metadata?.harness === harness) {
1120
1191
  const ready = await refreshRuntimeConnection(client, found);
1121
1192
  if (await isReusableBox(ready, harness, shell.livenessProbe)) {
1122
- const written = await materializeDeferredFilesForExistingBox(
1123
- shell,
1124
- client,
1125
- ready,
1126
- "reused",
1127
- name,
1128
- workspaceId,
1129
- userId,
1130
- harness
1131
- );
1132
- if (!written.succeeded) {
1133
- throw deferredProfileWriteFailed("reused", name, written.error);
1134
- }
1135
- const reusedBox = written.value;
1136
- if (shell.bootstrap) {
1137
- const boot = await shell.bootstrap(reusedBox, scope);
1138
- if (!boot.succeeded) {
1139
- throw new Error(`bootstrap failed on reused box ${name}`, { cause: boot.error });
1140
- }
1141
- }
1142
- return reusedBox;
1143
- }
1144
- const dropped = await deleteBox(ready);
1145
- if (!dropped.succeeded) {
1146
- throw new Error(
1147
- `sandbox ${name} (was ${String(found.metadata?.harness ?? "unknown")}, want ${harness}, or unresponsive) could not be deleted`,
1148
- { cause: dropped.error }
1149
- );
1193
+ return finalizeExistingBox(shell, client, ready, "reused", name, workspaceId, userId, harness, scope);
1150
1194
  }
1195
+ const recovered = await recoverUnresponsiveBox(
1196
+ client,
1197
+ ready,
1198
+ harness,
1199
+ shell.livenessProbe,
1200
+ "reused",
1201
+ name,
1202
+ resumeTimeout,
1203
+ onProgress
1204
+ );
1205
+ return finalizeExistingBox(shell, client, recovered, "reused", name, workspaceId, userId, harness, scope);
1151
1206
  } else {
1152
1207
  const dropped = await deleteBox(found);
1153
1208
  if (!dropped.succeeded) {
1154
1209
  throw new Error(
1155
- `sandbox ${name} (was ${String(found.metadata?.harness ?? "unknown")}, want ${harness}, or unresponsive) could not be deleted`,
1210
+ `sandbox ${name} (was ${String(found.metadata?.harness ?? "unknown")}, want ${harness}) could not be deleted`,
1156
1211
  { cause: dropped.error }
1157
1212
  );
1158
1213
  }
@@ -1185,35 +1240,19 @@ async function ensureWorkspaceSandbox(shell, options) {
1185
1240
  } else {
1186
1241
  const box2 = await refreshRuntimeConnection(client, resumed.value);
1187
1242
  if (await isReusableBox(box2, harness, shell.livenessProbe)) {
1188
- const written = await materializeDeferredFilesForExistingBox(
1189
- shell,
1190
- client,
1191
- box2,
1192
- "resumed",
1193
- name,
1194
- workspaceId,
1195
- userId,
1196
- harness
1197
- );
1198
- if (!written.succeeded) {
1199
- throw deferredProfileWriteFailed("resumed", name, written.error);
1200
- }
1201
- const resumedBox = written.value;
1202
- if (shell.bootstrap) {
1203
- const boot = await shell.bootstrap(resumedBox, scope);
1204
- if (!boot.succeeded) {
1205
- throw new Error(`bootstrap failed on resumed box ${name}`, { cause: boot.error });
1206
- }
1207
- }
1208
- return resumedBox;
1209
- }
1210
- const dropped = await deleteBox(box2);
1211
- if (!dropped.succeeded) {
1212
- throw new Error(
1213
- `resumed sandbox ${name} (was ${String(box2.metadata?.harness ?? "unknown")}, want ${harness}, or unresponsive) could not be deleted`,
1214
- { cause: dropped.error }
1215
- );
1243
+ return finalizeExistingBox(shell, client, box2, "resumed", name, workspaceId, userId, harness, scope);
1216
1244
  }
1245
+ const recovered = await recoverUnresponsiveBox(
1246
+ client,
1247
+ box2,
1248
+ harness,
1249
+ shell.livenessProbe,
1250
+ "resumed",
1251
+ name,
1252
+ resumeTimeout,
1253
+ onProgress
1254
+ );
1255
+ return finalizeExistingBox(shell, client, recovered, "resumed", name, workspaceId, userId, harness, scope);
1217
1256
  }
1218
1257
  }
1219
1258
  }
@@ -1645,6 +1684,7 @@ export {
1645
1684
  runSandboxToolPathSetup,
1646
1685
  splitDeferredProfileFiles,
1647
1686
  SandboxRuntimeAuthRefreshError,
1687
+ SandboxRecoveryFailedError,
1648
1688
  writeProfileFilesToBox,
1649
1689
  deferredCorpusHash,
1650
1690
  PROVISION_PAYLOAD_MAX_BYTES,
@@ -1675,4 +1715,4 @@ export {
1675
1715
  isTerminalPromptEvent,
1676
1716
  detectInteractiveQuestion
1677
1717
  };
1678
- //# sourceMappingURL=chunk-2ZSSOYXP.js.map
1718
+ //# sourceMappingURL=chunk-ALGZJBW2.js.map