@enclave-run/sdk 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -60,7 +60,7 @@ import createClient from "openapi-fetch";
60
60
  import platform2 from "platform";
61
61
 
62
62
  // package.json
63
- var version = "0.3.0";
63
+ var version = "0.4.0";
64
64
 
65
65
  // src/utils.ts
66
66
  import platform from "platform";
@@ -936,6 +936,7 @@ var ENVD_DEBUG_FALLBACK = "99.99.99";
936
936
  var ENVD_COMMANDS_STDIN = "0.3.0";
937
937
  var ENVD_DEFAULT_USER = "0.4.0";
938
938
  var ENVD_ENVD_CLOSE = "0.5.2";
939
+ var ENVD_PROCESS_RESUME = "1.1.0";
939
940
 
940
941
  // src/envd/rpc.ts
941
942
  function handleRpcError(err) {
@@ -2610,21 +2611,119 @@ import { createConnectTransport } from "@connectrpc/connect-web";
2610
2611
 
2611
2612
  // src/sandbox/commands/index.ts
2612
2613
  import {
2613
- Code as Code5,
2614
- ConnectError as ConnectError5,
2614
+ Code as Code6,
2615
+ ConnectError as ConnectError6,
2615
2616
  createClient as createClient5
2616
2617
  } from "@connectrpc/connect";
2617
2618
  import { compareVersions as compareVersions3 } from "compare-versions";
2618
2619
 
2619
2620
  // src/envd/process/process_pb.ts
2620
2621
  import { enumDesc as enumDesc2, fileDesc as fileDesc2, messageDesc as messageDesc2, serviceDesc as serviceDesc2 } from "@bufbuild/protobuf/codegenv2";
2621
- var file_process_process = /* @__PURE__ */ fileDesc2("ChVwcm9jZXNzL3Byb2Nlc3MucHJvdG8SB3Byb2Nlc3MiSgoDUFRZEh8KBHNpemUYASABKAsyES5wcm9jZXNzLlBUWS5TaXplGiIKBFNpemUSDAoEY29scxgBIAEoDRIMCgRyb3dzGAIgASgNIqEBCg1Qcm9jZXNzQ29uZmlnEgsKA2NtZBgBIAEoCRIMCgRhcmdzGAIgAygJEi4KBGVudnMYAyADKAsyIC5wcm9jZXNzLlByb2Nlc3NDb25maWcuRW52c0VudHJ5EhAKA2N3ZBgEIAEoCUgAiAEBGisKCUVudnNFbnRyeRILCgNrZXkYASABKAkSDQoFdmFsdWUYAiABKAk6AjgBQgYKBF9jd2QiDQoLTGlzdFJlcXVlc3QiXAoLUHJvY2Vzc0luZm8SJgoGY29uZmlnGAEgASgLMhYucHJvY2Vzcy5Qcm9jZXNzQ29uZmlnEgsKA3BpZBgCIAEoDRIQCgN0YWcYAyABKAlIAIgBAUIGCgRfdGFnIjcKDExpc3RSZXNwb25zZRInCglwcm9jZXNzZXMYASADKAsyFC5wcm9jZXNzLlByb2Nlc3NJbmZvIpcBCgxTdGFydFJlcXVlc3QSJwoHcHJvY2VzcxgBIAEoCzIWLnByb2Nlc3MuUHJvY2Vzc0NvbmZpZxIeCgNwdHkYAiABKAsyDC5wcm9jZXNzLlBUWUgAiAEBEhAKA3RhZxgDIAEoCUgBiAEBEhIKBXN0ZGluGAQgASgISAKIAQFCBgoEX3B0eUIGCgRfdGFnQggKBl9zdGRpbiJiCg1VcGRhdGVSZXF1ZXN0EikKB3Byb2Nlc3MYASABKAsyGC5wcm9jZXNzLlByb2Nlc3NTZWxlY3RvchIeCgNwdHkYAiABKAsyDC5wcm9jZXNzLlBUWUgAiAEBQgYKBF9wdHkiEAoOVXBkYXRlUmVzcG9uc2UirwMKDFByb2Nlc3NFdmVudBIxCgVzdGFydBgBIAEoCzIgLnByb2Nlc3MuUHJvY2Vzc0V2ZW50LlN0YXJ0RXZlbnRIABIvCgRkYXRhGAIgASgLMh8ucHJvY2Vzcy5Qcm9jZXNzRXZlbnQuRGF0YUV2ZW50SAASLQoDZW5kGAMgASgLMh4ucHJvY2Vzcy5Qcm9jZXNzRXZlbnQuRW5kRXZlbnRIABI0CglrZWVwYWxpdmUYBCABKAsyHy5wcm9jZXNzLlByb2Nlc3NFdmVudC5LZWVwQWxpdmVIABoZCgpTdGFydEV2ZW50EgsKA3BpZBgBIAEoDRpICglEYXRhRXZlbnQSEAoGc3Rkb3V0GAEgASgMSAASEAoGc3RkZXJyGAIgASgMSAASDQoDcHR5GAMgASgMSABCCAoGb3V0cHV0GlsKCEVuZEV2ZW50EhEKCWV4aXRfY29kZRgBIAEoERIOCgZleGl0ZWQYAiABKAgSDgoGc3RhdHVzGAMgASgJEhIKBWVycm9yGAQgASgJSACIAQFCCAoGX2Vycm9yGgsKCUtlZXBBbGl2ZUIHCgVldmVudCI1Cg1TdGFydFJlc3BvbnNlEiQKBWV2ZW50GAEgASgLMhUucHJvY2Vzcy5Qcm9jZXNzRXZlbnQiNwoPQ29ubmVjdFJlc3BvbnNlEiQKBWV2ZW50GAEgASgLMhUucHJvY2Vzcy5Qcm9jZXNzRXZlbnQiYwoQU2VuZElucHV0UmVxdWVzdBIpCgdwcm9jZXNzGAEgASgLMhgucHJvY2Vzcy5Qcm9jZXNzU2VsZWN0b3ISJAoFaW5wdXQYAiABKAsyFS5wcm9jZXNzLlByb2Nlc3NJbnB1dCITChFTZW5kSW5wdXRSZXNwb25zZSI3CgxQcm9jZXNzSW5wdXQSDwoFc3RkaW4YASABKAxIABINCgNwdHkYAiABKAxIAEIHCgVpbnB1dCLCAgoSU3RyZWFtSW5wdXRSZXF1ZXN0EjcKBXN0YXJ0GAEgASgLMiYucHJvY2Vzcy5TdHJlYW1JbnB1dFJlcXVlc3QuU3RhcnRFdmVudEgAEjUKBGRhdGEYAiABKAsyJS5wcm9jZXNzLlN0cmVhbUlucHV0UmVxdWVzdC5EYXRhRXZlbnRIABI6CglrZWVwYWxpdmUYAyABKAsyJS5wcm9jZXNzLlN0cmVhbUlucHV0UmVxdWVzdC5LZWVwQWxpdmVIABo3CgpTdGFydEV2ZW50EikKB3Byb2Nlc3MYASABKAsyGC5wcm9jZXNzLlByb2Nlc3NTZWxlY3RvchoxCglEYXRhRXZlbnQSJAoFaW5wdXQYAiABKAsyFS5wcm9jZXNzLlByb2Nlc3NJbnB1dBoLCglLZWVwQWxpdmVCBwoFZXZlbnQiFQoTU3RyZWFtSW5wdXRSZXNwb25zZSJfChFTZW5kU2lnbmFsUmVxdWVzdBIpCgdwcm9jZXNzGAEgASgLMhgucHJvY2Vzcy5Qcm9jZXNzU2VsZWN0b3ISHwoGc2lnbmFsGAIgASgOMg8ucHJvY2Vzcy5TaWduYWwiFAoSU2VuZFNpZ25hbFJlc3BvbnNlIj4KEUNsb3NlU3RkaW5SZXF1ZXN0EikKB3Byb2Nlc3MYASABKAsyGC5wcm9jZXNzLlByb2Nlc3NTZWxlY3RvciIUChJDbG9zZVN0ZGluUmVzcG9uc2UiOwoOQ29ubmVjdFJlcXVlc3QSKQoHcHJvY2VzcxgBIAEoCzIYLnByb2Nlc3MuUHJvY2Vzc1NlbGVjdG9yIjsKD1Byb2Nlc3NTZWxlY3RvchINCgNwaWQYASABKA1IABINCgN0YWcYAiABKAlIAEIKCghzZWxlY3RvcipICgZTaWduYWwSFgoSU0lHTkFMX1VOU1BFQ0lGSUVEEAASEgoOU0lHTkFMX1NJR1RFUk0QDxISCg5TSUdOQUxfU0lHS0lMTBAJMpEECgdQcm9jZXNzEjMKBExpc3QSFC5wcm9jZXNzLkxpc3RSZXF1ZXN0GhUucHJvY2Vzcy5MaXN0UmVzcG9uc2USPgoHQ29ubmVjdBIXLnByb2Nlc3MuQ29ubmVjdFJlcXVlc3QaGC5wcm9jZXNzLkNvbm5lY3RSZXNwb25zZTABEjgKBVN0YXJ0EhUucHJvY2Vzcy5TdGFydFJlcXVlc3QaFi5wcm9jZXNzLlN0YXJ0UmVzcG9uc2UwARI5CgZVcGRhdGUSFi5wcm9jZXNzLlVwZGF0ZVJlcXVlc3QaFy5wcm9jZXNzLlVwZGF0ZVJlc3BvbnNlEkoKC1N0cmVhbUlucHV0EhsucHJvY2Vzcy5TdHJlYW1JbnB1dFJlcXVlc3QaHC5wcm9jZXNzLlN0cmVhbUlucHV0UmVzcG9uc2UoARJCCglTZW5kSW5wdXQSGS5wcm9jZXNzLlNlbmRJbnB1dFJlcXVlc3QaGi5wcm9jZXNzLlNlbmRJbnB1dFJlc3BvbnNlEkUKClNlbmRTaWduYWwSGi5wcm9jZXNzLlNlbmRTaWduYWxSZXF1ZXN0GhsucHJvY2Vzcy5TZW5kU2lnbmFsUmVzcG9uc2USRQoKQ2xvc2VTdGRpbhIaLnByb2Nlc3MuQ2xvc2VTdGRpblJlcXVlc3QaGy5wcm9jZXNzLkNsb3NlU3RkaW5SZXNwb25zZUJXCgtjb20ucHJvY2Vzc0IMUHJvY2Vzc1Byb3RvUAGiAgNQWFiqAgdQcm9jZXNzygIHUHJvY2Vzc+ICE1Byb2Nlc3NcR1BCTWV0YWRhdGHqAgdQcm9jZXNzYgZwcm90bzM");
2622
+ var file_process_process = /* @__PURE__ */ fileDesc2("ChVwcm9jZXNzL3Byb2Nlc3MucHJvdG8SB3Byb2Nlc3MiSgoDUFRZEh8KBHNpemUYASABKAsyES5wcm9jZXNzLlBUWS5TaXplGiIKBFNpemUSDAoEY29scxgBIAEoDRIMCgRyb3dzGAIgASgNIqEBCg1Qcm9jZXNzQ29uZmlnEgsKA2NtZBgBIAEoCRIMCgRhcmdzGAIgAygJEi4KBGVudnMYAyADKAsyIC5wcm9jZXNzLlByb2Nlc3NDb25maWcuRW52c0VudHJ5EhAKA2N3ZBgEIAEoCUgAiAEBGisKCUVudnNFbnRyeRILCgNrZXkYASABKAkSDQoFdmFsdWUYAiABKAk6AjgBQgYKBF9jd2QiDQoLTGlzdFJlcXVlc3QiXAoLUHJvY2Vzc0luZm8SJgoGY29uZmlnGAEgASgLMhYucHJvY2Vzcy5Qcm9jZXNzQ29uZmlnEgsKA3BpZBgCIAEoDRIQCgN0YWcYAyABKAlIAIgBAUIGCgRfdGFnIjcKDExpc3RSZXNwb25zZRInCglwcm9jZXNzZXMYASADKAsyFC5wcm9jZXNzLlByb2Nlc3NJbmZvIskBCgxTdGFydFJlcXVlc3QSJwoHcHJvY2VzcxgBIAEoCzIWLnByb2Nlc3MuUHJvY2Vzc0NvbmZpZxIeCgNwdHkYAiABKAsyDC5wcm9jZXNzLlBUWUgAiAEBEhAKA3RhZxgDIAEoCUgBiAEBEhIKBXN0ZGluGAQgASgISAKIAQESHAoPaWRlbXBvdGVuY3lfa2V5GAUgASgJSAOIAQFCBgoEX3B0eUIGCgRfdGFnQggKBl9zdGRpbkISChBfaWRlbXBvdGVuY3lfa2V5ImIKDVVwZGF0ZVJlcXVlc3QSKQoHcHJvY2VzcxgBIAEoCzIYLnByb2Nlc3MuUHJvY2Vzc1NlbGVjdG9yEh4KA3B0eRgCIAEoCzIMLnByb2Nlc3MuUFRZSACIAQFCBgoEX3B0eSIQCg5VcGRhdGVSZXNwb25zZSLBAwoMUHJvY2Vzc0V2ZW50EjEKBXN0YXJ0GAEgASgLMiAucHJvY2Vzcy5Qcm9jZXNzRXZlbnQuU3RhcnRFdmVudEgAEi8KBGRhdGEYAiABKAsyHy5wcm9jZXNzLlByb2Nlc3NFdmVudC5EYXRhRXZlbnRIABItCgNlbmQYAyABKAsyHi5wcm9jZXNzLlByb2Nlc3NFdmVudC5FbmRFdmVudEgAEjQKCWtlZXBhbGl2ZRgEIAEoCzIfLnByb2Nlc3MuUHJvY2Vzc0V2ZW50LktlZXBBbGl2ZUgAEhAKCHNlcXVlbmNlGAUgASgEGhkKClN0YXJ0RXZlbnQSCwoDcGlkGAEgASgNGkgKCURhdGFFdmVudBIQCgZzdGRvdXQYASABKAxIABIQCgZzdGRlcnIYAiABKAxIABINCgNwdHkYAyABKAxIAEIICgZvdXRwdXQaWwoIRW5kRXZlbnQSEQoJZXhpdF9jb2RlGAEgASgREg4KBmV4aXRlZBgCIAEoCBIOCgZzdGF0dXMYAyABKAkSEgoFZXJyb3IYBCABKAlIAIgBAUIICgZfZXJyb3IaCwoJS2VlcEFsaXZlQgcKBWV2ZW50IjUKDVN0YXJ0UmVzcG9uc2USJAoFZXZlbnQYASABKAsyFS5wcm9jZXNzLlByb2Nlc3NFdmVudCI3Cg9Db25uZWN0UmVzcG9uc2USJAoFZXZlbnQYASABKAsyFS5wcm9jZXNzLlByb2Nlc3NFdmVudCJjChBTZW5kSW5wdXRSZXF1ZXN0EikKB3Byb2Nlc3MYASABKAsyGC5wcm9jZXNzLlByb2Nlc3NTZWxlY3RvchIkCgVpbnB1dBgCIAEoCzIVLnByb2Nlc3MuUHJvY2Vzc0lucHV0IhMKEVNlbmRJbnB1dFJlc3BvbnNlIjcKDFByb2Nlc3NJbnB1dBIPCgVzdGRpbhgBIAEoDEgAEg0KA3B0eRgCIAEoDEgAQgcKBWlucHV0IsICChJTdHJlYW1JbnB1dFJlcXVlc3QSNwoFc3RhcnQYASABKAsyJi5wcm9jZXNzLlN0cmVhbUlucHV0UmVxdWVzdC5TdGFydEV2ZW50SAASNQoEZGF0YRgCIAEoCzIlLnByb2Nlc3MuU3RyZWFtSW5wdXRSZXF1ZXN0LkRhdGFFdmVudEgAEjoKCWtlZXBhbGl2ZRgDIAEoCzIlLnByb2Nlc3MuU3RyZWFtSW5wdXRSZXF1ZXN0LktlZXBBbGl2ZUgAGjcKClN0YXJ0RXZlbnQSKQoHcHJvY2VzcxgBIAEoCzIYLnByb2Nlc3MuUHJvY2Vzc1NlbGVjdG9yGjEKCURhdGFFdmVudBIkCgVpbnB1dBgCIAEoCzIVLnByb2Nlc3MuUHJvY2Vzc0lucHV0GgsKCUtlZXBBbGl2ZUIHCgVldmVudCIVChNTdHJlYW1JbnB1dFJlc3BvbnNlIl8KEVNlbmRTaWduYWxSZXF1ZXN0EikKB3Byb2Nlc3MYASABKAsyGC5wcm9jZXNzLlByb2Nlc3NTZWxlY3RvchIfCgZzaWduYWwYAiABKA4yDy5wcm9jZXNzLlNpZ25hbCIUChJTZW5kU2lnbmFsUmVzcG9uc2UiPgoRQ2xvc2VTdGRpblJlcXVlc3QSKQoHcHJvY2VzcxgBIAEoCzIYLnByb2Nlc3MuUHJvY2Vzc1NlbGVjdG9yIhQKEkNsb3NlU3RkaW5SZXNwb25zZSJrCg5Db25uZWN0UmVxdWVzdBIpCgdwcm9jZXNzGAEgASgLMhgucHJvY2Vzcy5Qcm9jZXNzU2VsZWN0b3ISGwoOYWZ0ZXJfc2VxdWVuY2UYAiABKARIAIgBAUIRCg9fYWZ0ZXJfc2VxdWVuY2UiOwoPUHJvY2Vzc1NlbGVjdG9yEg0KA3BpZBgBIAEoDUgAEg0KA3RhZxgCIAEoCUgAQgoKCHNlbGVjdG9yKkgKBlNpZ25hbBIWChJTSUdOQUxfVU5TUEVDSUZJRUQQABISCg5TSUdOQUxfU0lHVEVSTRAPEhIKDlNJR05BTF9TSUdLSUxMEAkykQQKB1Byb2Nlc3MSMwoETGlzdBIULnByb2Nlc3MuTGlzdFJlcXVlc3QaFS5wcm9jZXNzLkxpc3RSZXNwb25zZRI+CgdDb25uZWN0EhcucHJvY2Vzcy5Db25uZWN0UmVxdWVzdBoYLnByb2Nlc3MuQ29ubmVjdFJlc3BvbnNlMAESOAoFU3RhcnQSFS5wcm9jZXNzLlN0YXJ0UmVxdWVzdBoWLnByb2Nlc3MuU3RhcnRSZXNwb25zZTABEjkKBlVwZGF0ZRIWLnByb2Nlc3MuVXBkYXRlUmVxdWVzdBoXLnByb2Nlc3MuVXBkYXRlUmVzcG9uc2USSgoLU3RyZWFtSW5wdXQSGy5wcm9jZXNzLlN0cmVhbUlucHV0UmVxdWVzdBocLnByb2Nlc3MuU3RyZWFtSW5wdXRSZXNwb25zZSgBEkIKCVNlbmRJbnB1dBIZLnByb2Nlc3MuU2VuZElucHV0UmVxdWVzdBoaLnByb2Nlc3MuU2VuZElucHV0UmVzcG9uc2USRQoKU2VuZFNpZ25hbBIaLnByb2Nlc3MuU2VuZFNpZ25hbFJlcXVlc3QaGy5wcm9jZXNzLlNlbmRTaWduYWxSZXNwb25zZRJFCgpDbG9zZVN0ZGluEhoucHJvY2Vzcy5DbG9zZVN0ZGluUmVxdWVzdBobLnByb2Nlc3MuQ2xvc2VTdGRpblJlc3BvbnNlQlcKC2NvbS5wcm9jZXNzQgxQcm9jZXNzUHJvdG9QAaICA1BYWKoCB1Byb2Nlc3PKAgdQcm9jZXNz4gITUHJvY2Vzc1xHUEJNZXRhZGF0YeoCB1Byb2Nlc3NiBnByb3RvMw");
2622
2623
  var Process = /* @__PURE__ */ serviceDesc2(file_process_process, 0);
2623
2624
 
2625
+ // src/sandbox/commands/resumable.ts
2626
+ import { Code as Code4, ConnectError as ConnectError4 } from "@connectrpc/connect";
2627
+ var DEFAULT_ATTEMPTS = 3;
2628
+ var defaultBackoff = (attempt) => 250 * 2 ** (attempt - 1);
2629
+ var ZERO = BigInt(0);
2630
+ var ONE = BigInt(1);
2631
+ function isResumableError(err) {
2632
+ const code = ConnectError4.from(err).code;
2633
+ return code === Code4.Unavailable || code === Code4.Unknown || code === Code4.Aborted || // sbxd drops a subscriber that stopped reading and asks it to reconnect.
2634
+ code === Code4.ResourceExhausted;
2635
+ }
2636
+ function resumableProcessEvents(initial, reopen, opts) {
2637
+ return __asyncGenerator(this, null, function* () {
2638
+ var _a3, _b, _c, _d, _e, _f, _g;
2639
+ const maxAttempts = (_a3 = opts.maxAttempts) != null ? _a3 : DEFAULT_ATTEMPTS;
2640
+ const backoffMs = (_b = opts.backoffMs) != null ? _b : defaultBackoff;
2641
+ let stream2 = initial;
2642
+ let pid;
2643
+ let last = ZERO;
2644
+ let attempts = 0;
2645
+ let resumed = false;
2646
+ for (; ; ) {
2647
+ try {
2648
+ try {
2649
+ for (var iter = __forAwait(stream2), more, temp, error; more = !(temp = yield new __await(iter.next())).done; more = false) {
2650
+ const response = temp.value;
2651
+ const event = response.event;
2652
+ const kind = event == null ? void 0 : event.event.case;
2653
+ if (kind === "start") {
2654
+ if (resumed && pid !== void 0) {
2655
+ continue;
2656
+ }
2657
+ pid = event == null ? void 0 : event.event.value.pid;
2658
+ }
2659
+ const sequence = (_c = event == null ? void 0 : event.sequence) != null ? _c : ZERO;
2660
+ if (sequence > ZERO) {
2661
+ if (sequence <= last) {
2662
+ continue;
2663
+ }
2664
+ if (resumed && sequence > last + ONE) {
2665
+ (_e = (_d = opts.logger) == null ? void 0 : _d.warn) == null ? void 0 : _e.call(
2666
+ _d,
2667
+ `Process ${pid} output between events ${last} and ${sequence} was evicted before the reconnect`
2668
+ );
2669
+ }
2670
+ last = sequence;
2671
+ }
2672
+ attempts = 0;
2673
+ yield response;
2674
+ if (kind === "end") {
2675
+ return;
2676
+ }
2677
+ }
2678
+ } catch (temp) {
2679
+ error = [temp];
2680
+ } finally {
2681
+ try {
2682
+ more && (temp = iter.return) && (yield new __await(temp.call(iter)));
2683
+ } finally {
2684
+ if (error)
2685
+ throw error[0];
2686
+ }
2687
+ }
2688
+ return;
2689
+ } catch (err) {
2690
+ if (opts.signal.aborted || !isResumableError(err) || attempts >= maxAttempts) {
2691
+ throw err;
2692
+ }
2693
+ attempts += 1;
2694
+ (_g = (_f = opts.logger) == null ? void 0 : _f.debug) == null ? void 0 : _g.call(
2695
+ _f,
2696
+ `Process stream dropped (${ConnectError4.from(err).code}); reconnecting, attempt ${attempts}`
2697
+ );
2698
+ yield new __await(sleep(backoffMs(attempts), opts.signal));
2699
+ stream2 = reopen(pid, last);
2700
+ resumed = true;
2701
+ }
2702
+ }
2703
+ });
2704
+ }
2705
+ function sleep(ms, signal) {
2706
+ return new Promise((resolve, reject) => {
2707
+ if (signal.aborted) {
2708
+ reject(new ConnectError4("operation was aborted", Code4.Canceled));
2709
+ return;
2710
+ }
2711
+ const timer = setTimeout(() => {
2712
+ signal.removeEventListener("abort", onAbort);
2713
+ resolve();
2714
+ }, ms);
2715
+ const onAbort = () => {
2716
+ clearTimeout(timer);
2717
+ reject(new ConnectError4("operation was aborted", Code4.Canceled));
2718
+ };
2719
+ signal.addEventListener("abort", onAbort, { once: true });
2720
+ });
2721
+ }
2722
+
2624
2723
  // src/sandbox/commands/pty.ts
2625
2724
  import {
2626
- Code as Code4,
2627
- ConnectError as ConnectError4,
2725
+ Code as Code5,
2726
+ ConnectError as ConnectError5,
2628
2727
  createClient as createClient4
2629
2728
  } from "@connectrpc/connect";
2630
2729
  var Pty = class {
@@ -2830,8 +2929,8 @@ var Pty = class {
2830
2929
  );
2831
2930
  return true;
2832
2931
  } catch (err) {
2833
- if (err instanceof ConnectError4) {
2834
- if (err.code === Code4.NotFound) {
2932
+ if (err instanceof ConnectError5) {
2933
+ if (err.code === Code5.NotFound) {
2835
2934
  return false;
2836
2935
  }
2837
2936
  }
@@ -2841,6 +2940,19 @@ var Pty = class {
2841
2940
  };
2842
2941
 
2843
2942
  // src/sandbox/commands/index.ts
2943
+ function remainingMs(deadline) {
2944
+ if (deadline === void 0) {
2945
+ return void 0;
2946
+ }
2947
+ const remaining = deadline - Date.now();
2948
+ if (remaining <= 0) {
2949
+ throw new ConnectError6(
2950
+ "process stream deadline exceeded",
2951
+ Code6.DeadlineExceeded
2952
+ );
2953
+ }
2954
+ return remaining;
2955
+ }
2844
2956
  var Commands = class {
2845
2957
  constructor(transport, connectionConfig, metadata) {
2846
2958
  this.connectionConfig = connectionConfig;
@@ -2855,6 +2967,14 @@ var Commands = class {
2855
2967
  get supportsStdinClose() {
2856
2968
  return compareVersions3(this.envdVersion, ENVD_ENVD_CLOSE) >= 0;
2857
2969
  }
2970
+ /**
2971
+ * sbxd 1.1.0+ numbers process output and accepts idempotent starts, so a
2972
+ * dropped command stream can be resumed without losing or repeating
2973
+ * output, and a retried start never runs the command twice.
2974
+ */
2975
+ get supportsProcessResume() {
2976
+ return compareVersions3(this.envdVersion, ENVD_PROCESS_RESUME) >= 0;
2977
+ }
2858
2978
  /**
2859
2979
  * List all running commands and PTY sessions.
2860
2980
  *
@@ -2969,8 +3089,8 @@ var Commands = class {
2969
3089
  );
2970
3090
  return true;
2971
3091
  } catch (err) {
2972
- if (err instanceof ConnectError5) {
2973
- if (err.code === Code5.NotFound) {
3092
+ if (err instanceof ConnectError6) {
3093
+ if (err.code === Code6.NotFound) {
2974
3094
  return false;
2975
3095
  }
2976
3096
  }
@@ -2993,23 +3113,31 @@ var Commands = class {
2993
3113
  const reqTimeout = requestTimeoutMs ? setTimeout(() => {
2994
3114
  controller.abort();
2995
3115
  }, requestTimeoutMs) : void 0;
2996
- const events = this.rpc.connect(
3116
+ const timeoutMs = (_b = opts == null ? void 0 : opts.timeoutMs) != null ? _b : this.defaultProcessConnectionTimeout;
3117
+ const deadline = timeoutMs ? Date.now() + timeoutMs : void 0;
3118
+ const connectTo = (afterSequence, remaining = timeoutMs) => this.rpc.connect(
2997
3119
  {
2998
3120
  process: {
2999
3121
  selector: {
3000
3122
  case: "pid",
3001
3123
  value: pid
3002
3124
  }
3003
- }
3125
+ },
3126
+ afterSequence
3004
3127
  },
3005
3128
  {
3006
3129
  signal: controller.signal,
3007
3130
  headers: {
3008
3131
  [KEEPALIVE_PING_HEADER]: KEEPALIVE_PING_INTERVAL_SEC.toString()
3009
3132
  },
3010
- timeoutMs: (_b = opts == null ? void 0 : opts.timeoutMs) != null ? _b : this.defaultProcessConnectionTimeout
3133
+ timeoutMs: remaining
3011
3134
  }
3012
3135
  );
3136
+ const events = this.supportsProcessResume ? resumableProcessEvents(
3137
+ connectTo(),
3138
+ (_, afterSequence) => connectTo(afterSequence, remainingMs(deadline)),
3139
+ { signal: controller.signal, logger: this.connectionConfig.logger }
3140
+ ) : connectTo();
3013
3141
  try {
3014
3142
  const pid2 = await handleProcessStartEvent(events);
3015
3143
  clearTimeout(reqTimeout);
@@ -3042,24 +3170,39 @@ var Commands = class {
3042
3170
  `Sandbox envd version ${this.envdVersion} can't specify stdin, it's always turned on. Please rebuild your template if you need this feature.`
3043
3171
  );
3044
3172
  }
3045
- const events = this.rpc.start(
3046
- {
3047
- process: {
3048
- cmd: "/bin/bash",
3049
- cwd: opts == null ? void 0 : opts.cwd,
3050
- envs: opts == null ? void 0 : opts.envs,
3051
- args: ["-l", "-c", cmd]
3052
- },
3053
- stdin: (opts == null ? void 0 : opts.stdin) || false
3173
+ const resume = this.supportsProcessResume;
3174
+ const request = {
3175
+ process: {
3176
+ cmd: "/bin/bash",
3177
+ cwd: opts == null ? void 0 : opts.cwd,
3178
+ envs: opts == null ? void 0 : opts.envs,
3179
+ args: ["-l", "-c", cmd]
3054
3180
  },
3055
- {
3056
- headers: __spreadProps(__spreadValues({}, authenticationHeader(this.envdVersion, opts == null ? void 0 : opts.user)), {
3057
- [KEEPALIVE_PING_HEADER]: KEEPALIVE_PING_INTERVAL_SEC.toString()
3058
- }),
3059
- signal: controller.signal,
3060
- timeoutMs: (_b = opts == null ? void 0 : opts.timeoutMs) != null ? _b : this.defaultProcessConnectionTimeout
3061
- }
3062
- );
3181
+ stdin: (opts == null ? void 0 : opts.stdin) || false,
3182
+ // A retried start with the same key attaches to the first one.
3183
+ idempotencyKey: resume ? crypto.randomUUID() : void 0
3184
+ };
3185
+ const timeoutMs = (_b = opts == null ? void 0 : opts.timeoutMs) != null ? _b : this.defaultProcessConnectionTimeout;
3186
+ const deadline = timeoutMs ? Date.now() + timeoutMs : void 0;
3187
+ const callOptions = (remaining) => ({
3188
+ headers: __spreadProps(__spreadValues({}, authenticationHeader(this.envdVersion, opts == null ? void 0 : opts.user)), {
3189
+ [KEEPALIVE_PING_HEADER]: KEEPALIVE_PING_INTERVAL_SEC.toString()
3190
+ }),
3191
+ signal: controller.signal,
3192
+ timeoutMs: remaining
3193
+ });
3194
+ const started = this.rpc.start(request, callOptions(timeoutMs));
3195
+ const events = resume ? resumableProcessEvents(
3196
+ started,
3197
+ (pid, afterSequence) => pid === void 0 ? this.rpc.start(request, callOptions(remainingMs(deadline))) : this.rpc.connect(
3198
+ {
3199
+ process: { selector: { case: "pid", value: pid } },
3200
+ afterSequence
3201
+ },
3202
+ callOptions(remainingMs(deadline))
3203
+ ),
3204
+ { signal: controller.signal, logger: this.connectionConfig.logger }
3205
+ ) : started;
3063
3206
  try {
3064
3207
  const pid = await handleProcessStartEvent(events);
3065
3208
  clearTimeout(reqTimeout);