@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.d.mts CHANGED
@@ -4348,6 +4348,15 @@ type StartRequest = Message<"process.StartRequest"> & {
4348
4348
  * @generated from field: optional bool stdin = 4;
4349
4349
  */
4350
4350
  stdin?: boolean;
4351
+ /**
4352
+ * A retried Start with the same key attaches to the process the first
4353
+ * Start launched (replaying its retained output) instead of running the
4354
+ * command again. Keys are kept while the process runs and for a short
4355
+ * retention window after it exits.
4356
+ *
4357
+ * @generated from field: optional string idempotency_key = 5;
4358
+ */
4359
+ idempotencyKey?: string;
4351
4360
  };
4352
4361
  /**
4353
4362
  * Describes the message process.StartRequest.
@@ -4416,6 +4425,15 @@ type ProcessEvent = Message<"process.ProcessEvent"> & {
4416
4425
  case: undefined;
4417
4426
  value?: undefined;
4418
4427
  };
4428
+ /**
4429
+ * Per-process position of a data or end event, starting at 1. Start and
4430
+ * keepalive events carry 0. A client that reconnects with
4431
+ * ConnectRequest.after_sequence receives every retained event after it;
4432
+ * a jump in the sequence means older output was evicted.
4433
+ *
4434
+ * @generated from field: uint64 sequence = 5;
4435
+ */
4436
+ sequence: bigint;
4419
4437
  };
4420
4438
  /**
4421
4439
  * @generated from message process.ProcessEvent.StartEvent
@@ -4684,6 +4702,15 @@ type ConnectRequest = Message<"process.ConnectRequest"> & {
4684
4702
  * @generated from field: process.ProcessSelector process = 1;
4685
4703
  */
4686
4704
  process?: ProcessSelector;
4705
+ /**
4706
+ * Replay retained events with a greater sequence before streaming live
4707
+ * ones. Unset streams live events only. An exited process stays
4708
+ * connectable for a short retention window and always ends with its
4709
+ * end event (exit code).
4710
+ *
4711
+ * @generated from field: optional uint64 after_sequence = 2;
4712
+ */
4713
+ afterSequence?: bigint;
4687
4714
  };
4688
4715
  /**
4689
4716
  * Describes the message process.ConnectRequest.
@@ -7897,6 +7924,12 @@ declare class Commands {
7897
7924
  * @internal
7898
7925
  */
7899
7926
  get supportsStdinClose(): boolean;
7927
+ /**
7928
+ * sbxd 1.1.0+ numbers process output and accepts idempotent starts, so a
7929
+ * dropped command stream can be resumed without losing or repeating
7930
+ * output, and a retried start never runs the command twice.
7931
+ */
7932
+ private get supportsProcessResume();
7900
7933
  /**
7901
7934
  * List all running commands and PTY sessions.
7902
7935
  *
package/dist/index.d.ts CHANGED
@@ -4348,6 +4348,15 @@ type StartRequest = Message<"process.StartRequest"> & {
4348
4348
  * @generated from field: optional bool stdin = 4;
4349
4349
  */
4350
4350
  stdin?: boolean;
4351
+ /**
4352
+ * A retried Start with the same key attaches to the process the first
4353
+ * Start launched (replaying its retained output) instead of running the
4354
+ * command again. Keys are kept while the process runs and for a short
4355
+ * retention window after it exits.
4356
+ *
4357
+ * @generated from field: optional string idempotency_key = 5;
4358
+ */
4359
+ idempotencyKey?: string;
4351
4360
  };
4352
4361
  /**
4353
4362
  * Describes the message process.StartRequest.
@@ -4416,6 +4425,15 @@ type ProcessEvent = Message<"process.ProcessEvent"> & {
4416
4425
  case: undefined;
4417
4426
  value?: undefined;
4418
4427
  };
4428
+ /**
4429
+ * Per-process position of a data or end event, starting at 1. Start and
4430
+ * keepalive events carry 0. A client that reconnects with
4431
+ * ConnectRequest.after_sequence receives every retained event after it;
4432
+ * a jump in the sequence means older output was evicted.
4433
+ *
4434
+ * @generated from field: uint64 sequence = 5;
4435
+ */
4436
+ sequence: bigint;
4419
4437
  };
4420
4438
  /**
4421
4439
  * @generated from message process.ProcessEvent.StartEvent
@@ -4684,6 +4702,15 @@ type ConnectRequest = Message<"process.ConnectRequest"> & {
4684
4702
  * @generated from field: process.ProcessSelector process = 1;
4685
4703
  */
4686
4704
  process?: ProcessSelector;
4705
+ /**
4706
+ * Replay retained events with a greater sequence before streaming live
4707
+ * ones. Unset streams live events only. An exited process stays
4708
+ * connectable for a short retention window and always ends with its
4709
+ * end event (exit code).
4710
+ *
4711
+ * @generated from field: optional uint64 after_sequence = 2;
4712
+ */
4713
+ afterSequence?: bigint;
4687
4714
  };
4688
4715
  /**
4689
4716
  * Describes the message process.ConnectRequest.
@@ -7897,6 +7924,12 @@ declare class Commands {
7897
7924
  * @internal
7898
7925
  */
7899
7926
  get supportsStdinClose(): boolean;
7927
+ /**
7928
+ * sbxd 1.1.0+ numbers process output and accepts idempotent starts, so a
7929
+ * dropped command stream can be resumed without losing or repeating
7930
+ * output, and a retried start never runs the command twice.
7931
+ */
7932
+ private get supportsProcessResume();
7900
7933
  /**
7901
7934
  * List all running commands and PTY sessions.
7902
7935
  *
package/dist/index.js CHANGED
@@ -128,7 +128,7 @@ var import_openapi_fetch = __toESM(require("openapi-fetch"));
128
128
  var import_platform2 = __toESM(require("platform"));
129
129
 
130
130
  // package.json
131
- var version = "0.3.0";
131
+ var version = "0.4.0";
132
132
 
133
133
  // src/utils.ts
134
134
  var import_platform = __toESM(require("platform"));
@@ -1000,6 +1000,7 @@ var ENVD_DEBUG_FALLBACK = "99.99.99";
1000
1000
  var ENVD_COMMANDS_STDIN = "0.3.0";
1001
1001
  var ENVD_DEFAULT_USER = "0.4.0";
1002
1002
  var ENVD_ENVD_CLOSE = "0.5.2";
1003
+ var ENVD_PROCESS_RESUME = "1.1.0";
1003
1004
 
1004
1005
  // src/envd/rpc.ts
1005
1006
  function handleRpcError(err) {
@@ -2673,23 +2674,121 @@ var Git = class {
2673
2674
  var import_connect_web = require("@connectrpc/connect-web");
2674
2675
 
2675
2676
  // src/sandbox/commands/index.ts
2676
- var import_connect5 = require("@connectrpc/connect");
2677
+ var import_connect6 = require("@connectrpc/connect");
2677
2678
  var import_compare_versions3 = require("compare-versions");
2678
2679
 
2679
2680
  // src/envd/process/process_pb.ts
2680
2681
  var import_codegenv22 = require("@bufbuild/protobuf/codegenv2");
2681
- var file_process_process = /* @__PURE__ */ (0, import_codegenv22.fileDesc)("ChVwcm9jZXNzL3Byb2Nlc3MucHJvdG8SB3Byb2Nlc3MiSgoDUFRZEh8KBHNpemUYASABKAsyES5wcm9jZXNzLlBUWS5TaXplGiIKBFNpemUSDAoEY29scxgBIAEoDRIMCgRyb3dzGAIgASgNIqEBCg1Qcm9jZXNzQ29uZmlnEgsKA2NtZBgBIAEoCRIMCgRhcmdzGAIgAygJEi4KBGVudnMYAyADKAsyIC5wcm9jZXNzLlByb2Nlc3NDb25maWcuRW52c0VudHJ5EhAKA2N3ZBgEIAEoCUgAiAEBGisKCUVudnNFbnRyeRILCgNrZXkYASABKAkSDQoFdmFsdWUYAiABKAk6AjgBQgYKBF9jd2QiDQoLTGlzdFJlcXVlc3QiXAoLUHJvY2Vzc0luZm8SJgoGY29uZmlnGAEgASgLMhYucHJvY2Vzcy5Qcm9jZXNzQ29uZmlnEgsKA3BpZBgCIAEoDRIQCgN0YWcYAyABKAlIAIgBAUIGCgRfdGFnIjcKDExpc3RSZXNwb25zZRInCglwcm9jZXNzZXMYASADKAsyFC5wcm9jZXNzLlByb2Nlc3NJbmZvIpcBCgxTdGFydFJlcXVlc3QSJwoHcHJvY2VzcxgBIAEoCzIWLnByb2Nlc3MuUHJvY2Vzc0NvbmZpZxIeCgNwdHkYAiABKAsyDC5wcm9jZXNzLlBUWUgAiAEBEhAKA3RhZxgDIAEoCUgBiAEBEhIKBXN0ZGluGAQgASgISAKIAQFCBgoEX3B0eUIGCgRfdGFnQggKBl9zdGRpbiJiCg1VcGRhdGVSZXF1ZXN0EikKB3Byb2Nlc3MYASABKAsyGC5wcm9jZXNzLlByb2Nlc3NTZWxlY3RvchIeCgNwdHkYAiABKAsyDC5wcm9jZXNzLlBUWUgAiAEBQgYKBF9wdHkiEAoOVXBkYXRlUmVzcG9uc2UirwMKDFByb2Nlc3NFdmVudBIxCgVzdGFydBgBIAEoCzIgLnByb2Nlc3MuUHJvY2Vzc0V2ZW50LlN0YXJ0RXZlbnRIABIvCgRkYXRhGAIgASgLMh8ucHJvY2Vzcy5Qcm9jZXNzRXZlbnQuRGF0YUV2ZW50SAASLQoDZW5kGAMgASgLMh4ucHJvY2Vzcy5Qcm9jZXNzRXZlbnQuRW5kRXZlbnRIABI0CglrZWVwYWxpdmUYBCABKAsyHy5wcm9jZXNzLlByb2Nlc3NFdmVudC5LZWVwQWxpdmVIABoZCgpTdGFydEV2ZW50EgsKA3BpZBgBIAEoDRpICglEYXRhRXZlbnQSEAoGc3Rkb3V0GAEgASgMSAASEAoGc3RkZXJyGAIgASgMSAASDQoDcHR5GAMgASgMSABCCAoGb3V0cHV0GlsKCEVuZEV2ZW50EhEKCWV4aXRfY29kZRgBIAEoERIOCgZleGl0ZWQYAiABKAgSDgoGc3RhdHVzGAMgASgJEhIKBWVycm9yGAQgASgJSACIAQFCCAoGX2Vycm9yGgsKCUtlZXBBbGl2ZUIHCgVldmVudCI1Cg1TdGFydFJlc3BvbnNlEiQKBWV2ZW50GAEgASgLMhUucHJvY2Vzcy5Qcm9jZXNzRXZlbnQiNwoPQ29ubmVjdFJlc3BvbnNlEiQKBWV2ZW50GAEgASgLMhUucHJvY2Vzcy5Qcm9jZXNzRXZlbnQiYwoQU2VuZElucHV0UmVxdWVzdBIpCgdwcm9jZXNzGAEgASgLMhgucHJvY2Vzcy5Qcm9jZXNzU2VsZWN0b3ISJAoFaW5wdXQYAiABKAsyFS5wcm9jZXNzLlByb2Nlc3NJbnB1dCITChFTZW5kSW5wdXRSZXNwb25zZSI3CgxQcm9jZXNzSW5wdXQSDwoFc3RkaW4YASABKAxIABINCgNwdHkYAiABKAxIAEIHCgVpbnB1dCLCAgoSU3RyZWFtSW5wdXRSZXF1ZXN0EjcKBXN0YXJ0GAEgASgLMiYucHJvY2Vzcy5TdHJlYW1JbnB1dFJlcXVlc3QuU3RhcnRFdmVudEgAEjUKBGRhdGEYAiABKAsyJS5wcm9jZXNzLlN0cmVhbUlucHV0UmVxdWVzdC5EYXRhRXZlbnRIABI6CglrZWVwYWxpdmUYAyABKAsyJS5wcm9jZXNzLlN0cmVhbUlucHV0UmVxdWVzdC5LZWVwQWxpdmVIABo3CgpTdGFydEV2ZW50EikKB3Byb2Nlc3MYASABKAsyGC5wcm9jZXNzLlByb2Nlc3NTZWxlY3RvchoxCglEYXRhRXZlbnQSJAoFaW5wdXQYAiABKAsyFS5wcm9jZXNzLlByb2Nlc3NJbnB1dBoLCglLZWVwQWxpdmVCBwoFZXZlbnQiFQoTU3RyZWFtSW5wdXRSZXNwb25zZSJfChFTZW5kU2lnbmFsUmVxdWVzdBIpCgdwcm9jZXNzGAEgASgLMhgucHJvY2Vzcy5Qcm9jZXNzU2VsZWN0b3ISHwoGc2lnbmFsGAIgASgOMg8ucHJvY2Vzcy5TaWduYWwiFAoSU2VuZFNpZ25hbFJlc3BvbnNlIj4KEUNsb3NlU3RkaW5SZXF1ZXN0EikKB3Byb2Nlc3MYASABKAsyGC5wcm9jZXNzLlByb2Nlc3NTZWxlY3RvciIUChJDbG9zZVN0ZGluUmVzcG9uc2UiOwoOQ29ubmVjdFJlcXVlc3QSKQoHcHJvY2VzcxgBIAEoCzIYLnByb2Nlc3MuUHJvY2Vzc1NlbGVjdG9yIjsKD1Byb2Nlc3NTZWxlY3RvchINCgNwaWQYASABKA1IABINCgN0YWcYAiABKAlIAEIKCghzZWxlY3RvcipICgZTaWduYWwSFgoSU0lHTkFMX1VOU1BFQ0lGSUVEEAASEgoOU0lHTkFMX1NJR1RFUk0QDxISCg5TSUdOQUxfU0lHS0lMTBAJMpEECgdQcm9jZXNzEjMKBExpc3QSFC5wcm9jZXNzLkxpc3RSZXF1ZXN0GhUucHJvY2Vzcy5MaXN0UmVzcG9uc2USPgoHQ29ubmVjdBIXLnByb2Nlc3MuQ29ubmVjdFJlcXVlc3QaGC5wcm9jZXNzLkNvbm5lY3RSZXNwb25zZTABEjgKBVN0YXJ0EhUucHJvY2Vzcy5TdGFydFJlcXVlc3QaFi5wcm9jZXNzLlN0YXJ0UmVzcG9uc2UwARI5CgZVcGRhdGUSFi5wcm9jZXNzLlVwZGF0ZVJlcXVlc3QaFy5wcm9jZXNzLlVwZGF0ZVJlc3BvbnNlEkoKC1N0cmVhbUlucHV0EhsucHJvY2Vzcy5TdHJlYW1JbnB1dFJlcXVlc3QaHC5wcm9jZXNzLlN0cmVhbUlucHV0UmVzcG9uc2UoARJCCglTZW5kSW5wdXQSGS5wcm9jZXNzLlNlbmRJbnB1dFJlcXVlc3QaGi5wcm9jZXNzLlNlbmRJbnB1dFJlc3BvbnNlEkUKClNlbmRTaWduYWwSGi5wcm9jZXNzLlNlbmRTaWduYWxSZXF1ZXN0GhsucHJvY2Vzcy5TZW5kU2lnbmFsUmVzcG9uc2USRQoKQ2xvc2VTdGRpbhIaLnByb2Nlc3MuQ2xvc2VTdGRpblJlcXVlc3QaGy5wcm9jZXNzLkNsb3NlU3RkaW5SZXNwb25zZUJXCgtjb20ucHJvY2Vzc0IMUHJvY2Vzc1Byb3RvUAGiAgNQWFiqAgdQcm9jZXNzygIHUHJvY2Vzc+ICE1Byb2Nlc3NcR1BCTWV0YWRhdGHqAgdQcm9jZXNzYgZwcm90bzM");
2682
+ var file_process_process = /* @__PURE__ */ (0, import_codegenv22.fileDesc)("ChVwcm9jZXNzL3Byb2Nlc3MucHJvdG8SB3Byb2Nlc3MiSgoDUFRZEh8KBHNpemUYASABKAsyES5wcm9jZXNzLlBUWS5TaXplGiIKBFNpemUSDAoEY29scxgBIAEoDRIMCgRyb3dzGAIgASgNIqEBCg1Qcm9jZXNzQ29uZmlnEgsKA2NtZBgBIAEoCRIMCgRhcmdzGAIgAygJEi4KBGVudnMYAyADKAsyIC5wcm9jZXNzLlByb2Nlc3NDb25maWcuRW52c0VudHJ5EhAKA2N3ZBgEIAEoCUgAiAEBGisKCUVudnNFbnRyeRILCgNrZXkYASABKAkSDQoFdmFsdWUYAiABKAk6AjgBQgYKBF9jd2QiDQoLTGlzdFJlcXVlc3QiXAoLUHJvY2Vzc0luZm8SJgoGY29uZmlnGAEgASgLMhYucHJvY2Vzcy5Qcm9jZXNzQ29uZmlnEgsKA3BpZBgCIAEoDRIQCgN0YWcYAyABKAlIAIgBAUIGCgRfdGFnIjcKDExpc3RSZXNwb25zZRInCglwcm9jZXNzZXMYASADKAsyFC5wcm9jZXNzLlByb2Nlc3NJbmZvIskBCgxTdGFydFJlcXVlc3QSJwoHcHJvY2VzcxgBIAEoCzIWLnByb2Nlc3MuUHJvY2Vzc0NvbmZpZxIeCgNwdHkYAiABKAsyDC5wcm9jZXNzLlBUWUgAiAEBEhAKA3RhZxgDIAEoCUgBiAEBEhIKBXN0ZGluGAQgASgISAKIAQESHAoPaWRlbXBvdGVuY3lfa2V5GAUgASgJSAOIAQFCBgoEX3B0eUIGCgRfdGFnQggKBl9zdGRpbkISChBfaWRlbXBvdGVuY3lfa2V5ImIKDVVwZGF0ZVJlcXVlc3QSKQoHcHJvY2VzcxgBIAEoCzIYLnByb2Nlc3MuUHJvY2Vzc1NlbGVjdG9yEh4KA3B0eRgCIAEoCzIMLnByb2Nlc3MuUFRZSACIAQFCBgoEX3B0eSIQCg5VcGRhdGVSZXNwb25zZSLBAwoMUHJvY2Vzc0V2ZW50EjEKBXN0YXJ0GAEgASgLMiAucHJvY2Vzcy5Qcm9jZXNzRXZlbnQuU3RhcnRFdmVudEgAEi8KBGRhdGEYAiABKAsyHy5wcm9jZXNzLlByb2Nlc3NFdmVudC5EYXRhRXZlbnRIABItCgNlbmQYAyABKAsyHi5wcm9jZXNzLlByb2Nlc3NFdmVudC5FbmRFdmVudEgAEjQKCWtlZXBhbGl2ZRgEIAEoCzIfLnByb2Nlc3MuUHJvY2Vzc0V2ZW50LktlZXBBbGl2ZUgAEhAKCHNlcXVlbmNlGAUgASgEGhkKClN0YXJ0RXZlbnQSCwoDcGlkGAEgASgNGkgKCURhdGFFdmVudBIQCgZzdGRvdXQYASABKAxIABIQCgZzdGRlcnIYAiABKAxIABINCgNwdHkYAyABKAxIAEIICgZvdXRwdXQaWwoIRW5kRXZlbnQSEQoJZXhpdF9jb2RlGAEgASgREg4KBmV4aXRlZBgCIAEoCBIOCgZzdGF0dXMYAyABKAkSEgoFZXJyb3IYBCABKAlIAIgBAUIICgZfZXJyb3IaCwoJS2VlcEFsaXZlQgcKBWV2ZW50IjUKDVN0YXJ0UmVzcG9uc2USJAoFZXZlbnQYASABKAsyFS5wcm9jZXNzLlByb2Nlc3NFdmVudCI3Cg9Db25uZWN0UmVzcG9uc2USJAoFZXZlbnQYASABKAsyFS5wcm9jZXNzLlByb2Nlc3NFdmVudCJjChBTZW5kSW5wdXRSZXF1ZXN0EikKB3Byb2Nlc3MYASABKAsyGC5wcm9jZXNzLlByb2Nlc3NTZWxlY3RvchIkCgVpbnB1dBgCIAEoCzIVLnByb2Nlc3MuUHJvY2Vzc0lucHV0IhMKEVNlbmRJbnB1dFJlc3BvbnNlIjcKDFByb2Nlc3NJbnB1dBIPCgVzdGRpbhgBIAEoDEgAEg0KA3B0eRgCIAEoDEgAQgcKBWlucHV0IsICChJTdHJlYW1JbnB1dFJlcXVlc3QSNwoFc3RhcnQYASABKAsyJi5wcm9jZXNzLlN0cmVhbUlucHV0UmVxdWVzdC5TdGFydEV2ZW50SAASNQoEZGF0YRgCIAEoCzIlLnByb2Nlc3MuU3RyZWFtSW5wdXRSZXF1ZXN0LkRhdGFFdmVudEgAEjoKCWtlZXBhbGl2ZRgDIAEoCzIlLnByb2Nlc3MuU3RyZWFtSW5wdXRSZXF1ZXN0LktlZXBBbGl2ZUgAGjcKClN0YXJ0RXZlbnQSKQoHcHJvY2VzcxgBIAEoCzIYLnByb2Nlc3MuUHJvY2Vzc1NlbGVjdG9yGjEKCURhdGFFdmVudBIkCgVpbnB1dBgCIAEoCzIVLnByb2Nlc3MuUHJvY2Vzc0lucHV0GgsKCUtlZXBBbGl2ZUIHCgVldmVudCIVChNTdHJlYW1JbnB1dFJlc3BvbnNlIl8KEVNlbmRTaWduYWxSZXF1ZXN0EikKB3Byb2Nlc3MYASABKAsyGC5wcm9jZXNzLlByb2Nlc3NTZWxlY3RvchIfCgZzaWduYWwYAiABKA4yDy5wcm9jZXNzLlNpZ25hbCIUChJTZW5kU2lnbmFsUmVzcG9uc2UiPgoRQ2xvc2VTdGRpblJlcXVlc3QSKQoHcHJvY2VzcxgBIAEoCzIYLnByb2Nlc3MuUHJvY2Vzc1NlbGVjdG9yIhQKEkNsb3NlU3RkaW5SZXNwb25zZSJrCg5Db25uZWN0UmVxdWVzdBIpCgdwcm9jZXNzGAEgASgLMhgucHJvY2Vzcy5Qcm9jZXNzU2VsZWN0b3ISGwoOYWZ0ZXJfc2VxdWVuY2UYAiABKARIAIgBAUIRCg9fYWZ0ZXJfc2VxdWVuY2UiOwoPUHJvY2Vzc1NlbGVjdG9yEg0KA3BpZBgBIAEoDUgAEg0KA3RhZxgCIAEoCUgAQgoKCHNlbGVjdG9yKkgKBlNpZ25hbBIWChJTSUdOQUxfVU5TUEVDSUZJRUQQABISCg5TSUdOQUxfU0lHVEVSTRAPEhIKDlNJR05BTF9TSUdLSUxMEAkykQQKB1Byb2Nlc3MSMwoETGlzdBIULnByb2Nlc3MuTGlzdFJlcXVlc3QaFS5wcm9jZXNzLkxpc3RSZXNwb25zZRI+CgdDb25uZWN0EhcucHJvY2Vzcy5Db25uZWN0UmVxdWVzdBoYLnByb2Nlc3MuQ29ubmVjdFJlc3BvbnNlMAESOAoFU3RhcnQSFS5wcm9jZXNzLlN0YXJ0UmVxdWVzdBoWLnByb2Nlc3MuU3RhcnRSZXNwb25zZTABEjkKBlVwZGF0ZRIWLnByb2Nlc3MuVXBkYXRlUmVxdWVzdBoXLnByb2Nlc3MuVXBkYXRlUmVzcG9uc2USSgoLU3RyZWFtSW5wdXQSGy5wcm9jZXNzLlN0cmVhbUlucHV0UmVxdWVzdBocLnByb2Nlc3MuU3RyZWFtSW5wdXRSZXNwb25zZSgBEkIKCVNlbmRJbnB1dBIZLnByb2Nlc3MuU2VuZElucHV0UmVxdWVzdBoaLnByb2Nlc3MuU2VuZElucHV0UmVzcG9uc2USRQoKU2VuZFNpZ25hbBIaLnByb2Nlc3MuU2VuZFNpZ25hbFJlcXVlc3QaGy5wcm9jZXNzLlNlbmRTaWduYWxSZXNwb25zZRJFCgpDbG9zZVN0ZGluEhoucHJvY2Vzcy5DbG9zZVN0ZGluUmVxdWVzdBobLnByb2Nlc3MuQ2xvc2VTdGRpblJlc3BvbnNlQlcKC2NvbS5wcm9jZXNzQgxQcm9jZXNzUHJvdG9QAaICA1BYWKoCB1Byb2Nlc3PKAgdQcm9jZXNz4gITUHJvY2Vzc1xHUEJNZXRhZGF0YeoCB1Byb2Nlc3NiBnByb3RvMw");
2682
2683
  var Process = /* @__PURE__ */ (0, import_codegenv22.serviceDesc)(file_process_process, 0);
2683
2684
 
2684
- // src/sandbox/commands/pty.ts
2685
+ // src/sandbox/commands/resumable.ts
2685
2686
  var import_connect4 = require("@connectrpc/connect");
2687
+ var DEFAULT_ATTEMPTS = 3;
2688
+ var defaultBackoff = (attempt) => 250 * 2 ** (attempt - 1);
2689
+ var ZERO = BigInt(0);
2690
+ var ONE = BigInt(1);
2691
+ function isResumableError(err) {
2692
+ const code = import_connect4.ConnectError.from(err).code;
2693
+ return code === import_connect4.Code.Unavailable || code === import_connect4.Code.Unknown || code === import_connect4.Code.Aborted || // sbxd drops a subscriber that stopped reading and asks it to reconnect.
2694
+ code === import_connect4.Code.ResourceExhausted;
2695
+ }
2696
+ function resumableProcessEvents(initial, reopen, opts) {
2697
+ return __asyncGenerator(this, null, function* () {
2698
+ var _a3, _b, _c, _d, _e, _f, _g;
2699
+ const maxAttempts = (_a3 = opts.maxAttempts) != null ? _a3 : DEFAULT_ATTEMPTS;
2700
+ const backoffMs = (_b = opts.backoffMs) != null ? _b : defaultBackoff;
2701
+ let stream2 = initial;
2702
+ let pid;
2703
+ let last = ZERO;
2704
+ let attempts = 0;
2705
+ let resumed = false;
2706
+ for (; ; ) {
2707
+ try {
2708
+ try {
2709
+ for (var iter = __forAwait(stream2), more, temp, error; more = !(temp = yield new __await(iter.next())).done; more = false) {
2710
+ const response = temp.value;
2711
+ const event = response.event;
2712
+ const kind = event == null ? void 0 : event.event.case;
2713
+ if (kind === "start") {
2714
+ if (resumed && pid !== void 0) {
2715
+ continue;
2716
+ }
2717
+ pid = event == null ? void 0 : event.event.value.pid;
2718
+ }
2719
+ const sequence = (_c = event == null ? void 0 : event.sequence) != null ? _c : ZERO;
2720
+ if (sequence > ZERO) {
2721
+ if (sequence <= last) {
2722
+ continue;
2723
+ }
2724
+ if (resumed && sequence > last + ONE) {
2725
+ (_e = (_d = opts.logger) == null ? void 0 : _d.warn) == null ? void 0 : _e.call(
2726
+ _d,
2727
+ `Process ${pid} output between events ${last} and ${sequence} was evicted before the reconnect`
2728
+ );
2729
+ }
2730
+ last = sequence;
2731
+ }
2732
+ attempts = 0;
2733
+ yield response;
2734
+ if (kind === "end") {
2735
+ return;
2736
+ }
2737
+ }
2738
+ } catch (temp) {
2739
+ error = [temp];
2740
+ } finally {
2741
+ try {
2742
+ more && (temp = iter.return) && (yield new __await(temp.call(iter)));
2743
+ } finally {
2744
+ if (error)
2745
+ throw error[0];
2746
+ }
2747
+ }
2748
+ return;
2749
+ } catch (err) {
2750
+ if (opts.signal.aborted || !isResumableError(err) || attempts >= maxAttempts) {
2751
+ throw err;
2752
+ }
2753
+ attempts += 1;
2754
+ (_g = (_f = opts.logger) == null ? void 0 : _f.debug) == null ? void 0 : _g.call(
2755
+ _f,
2756
+ `Process stream dropped (${import_connect4.ConnectError.from(err).code}); reconnecting, attempt ${attempts}`
2757
+ );
2758
+ yield new __await(sleep(backoffMs(attempts), opts.signal));
2759
+ stream2 = reopen(pid, last);
2760
+ resumed = true;
2761
+ }
2762
+ }
2763
+ });
2764
+ }
2765
+ function sleep(ms, signal) {
2766
+ return new Promise((resolve, reject) => {
2767
+ if (signal.aborted) {
2768
+ reject(new import_connect4.ConnectError("operation was aborted", import_connect4.Code.Canceled));
2769
+ return;
2770
+ }
2771
+ const timer = setTimeout(() => {
2772
+ signal.removeEventListener("abort", onAbort);
2773
+ resolve();
2774
+ }, ms);
2775
+ const onAbort = () => {
2776
+ clearTimeout(timer);
2777
+ reject(new import_connect4.ConnectError("operation was aborted", import_connect4.Code.Canceled));
2778
+ };
2779
+ signal.addEventListener("abort", onAbort, { once: true });
2780
+ });
2781
+ }
2782
+
2783
+ // src/sandbox/commands/pty.ts
2784
+ var import_connect5 = require("@connectrpc/connect");
2686
2785
  var Pty = class {
2687
2786
  // 60 seconds
2688
2787
  constructor(transport, connectionConfig, metadata) {
2689
2788
  this.transport = transport;
2690
2789
  this.connectionConfig = connectionConfig;
2691
2790
  this.defaultPtyConnectionTimeout = 6e4;
2692
- this.rpc = (0, import_connect4.createClient)(Process, this.transport);
2791
+ this.rpc = (0, import_connect5.createClient)(Process, this.transport);
2693
2792
  this.envdVersion = metadata.version;
2694
2793
  }
2695
2794
  /**
@@ -2886,8 +2985,8 @@ var Pty = class {
2886
2985
  );
2887
2986
  return true;
2888
2987
  } catch (err) {
2889
- if (err instanceof import_connect4.ConnectError) {
2890
- if (err.code === import_connect4.Code.NotFound) {
2988
+ if (err instanceof import_connect5.ConnectError) {
2989
+ if (err.code === import_connect5.Code.NotFound) {
2891
2990
  return false;
2892
2991
  }
2893
2992
  }
@@ -2897,11 +2996,24 @@ var Pty = class {
2897
2996
  };
2898
2997
 
2899
2998
  // src/sandbox/commands/index.ts
2999
+ function remainingMs(deadline) {
3000
+ if (deadline === void 0) {
3001
+ return void 0;
3002
+ }
3003
+ const remaining = deadline - Date.now();
3004
+ if (remaining <= 0) {
3005
+ throw new import_connect6.ConnectError(
3006
+ "process stream deadline exceeded",
3007
+ import_connect6.Code.DeadlineExceeded
3008
+ );
3009
+ }
3010
+ return remaining;
3011
+ }
2900
3012
  var Commands = class {
2901
3013
  constructor(transport, connectionConfig, metadata) {
2902
3014
  this.connectionConfig = connectionConfig;
2903
3015
  this.defaultProcessConnectionTimeout = 6e4;
2904
- this.rpc = (0, import_connect5.createClient)(Process, transport);
3016
+ this.rpc = (0, import_connect6.createClient)(Process, transport);
2905
3017
  this.envdVersion = metadata.version;
2906
3018
  }
2907
3019
  /**
@@ -2911,6 +3023,14 @@ var Commands = class {
2911
3023
  get supportsStdinClose() {
2912
3024
  return (0, import_compare_versions3.compareVersions)(this.envdVersion, ENVD_ENVD_CLOSE) >= 0;
2913
3025
  }
3026
+ /**
3027
+ * sbxd 1.1.0+ numbers process output and accepts idempotent starts, so a
3028
+ * dropped command stream can be resumed without losing or repeating
3029
+ * output, and a retried start never runs the command twice.
3030
+ */
3031
+ get supportsProcessResume() {
3032
+ return (0, import_compare_versions3.compareVersions)(this.envdVersion, ENVD_PROCESS_RESUME) >= 0;
3033
+ }
2914
3034
  /**
2915
3035
  * List all running commands and PTY sessions.
2916
3036
  *
@@ -3025,8 +3145,8 @@ var Commands = class {
3025
3145
  );
3026
3146
  return true;
3027
3147
  } catch (err) {
3028
- if (err instanceof import_connect5.ConnectError) {
3029
- if (err.code === import_connect5.Code.NotFound) {
3148
+ if (err instanceof import_connect6.ConnectError) {
3149
+ if (err.code === import_connect6.Code.NotFound) {
3030
3150
  return false;
3031
3151
  }
3032
3152
  }
@@ -3049,23 +3169,31 @@ var Commands = class {
3049
3169
  const reqTimeout = requestTimeoutMs ? setTimeout(() => {
3050
3170
  controller.abort();
3051
3171
  }, requestTimeoutMs) : void 0;
3052
- const events = this.rpc.connect(
3172
+ const timeoutMs = (_b = opts == null ? void 0 : opts.timeoutMs) != null ? _b : this.defaultProcessConnectionTimeout;
3173
+ const deadline = timeoutMs ? Date.now() + timeoutMs : void 0;
3174
+ const connectTo = (afterSequence, remaining = timeoutMs) => this.rpc.connect(
3053
3175
  {
3054
3176
  process: {
3055
3177
  selector: {
3056
3178
  case: "pid",
3057
3179
  value: pid
3058
3180
  }
3059
- }
3181
+ },
3182
+ afterSequence
3060
3183
  },
3061
3184
  {
3062
3185
  signal: controller.signal,
3063
3186
  headers: {
3064
3187
  [KEEPALIVE_PING_HEADER]: KEEPALIVE_PING_INTERVAL_SEC.toString()
3065
3188
  },
3066
- timeoutMs: (_b = opts == null ? void 0 : opts.timeoutMs) != null ? _b : this.defaultProcessConnectionTimeout
3189
+ timeoutMs: remaining
3067
3190
  }
3068
3191
  );
3192
+ const events = this.supportsProcessResume ? resumableProcessEvents(
3193
+ connectTo(),
3194
+ (_, afterSequence) => connectTo(afterSequence, remainingMs(deadline)),
3195
+ { signal: controller.signal, logger: this.connectionConfig.logger }
3196
+ ) : connectTo();
3069
3197
  try {
3070
3198
  const pid2 = await handleProcessStartEvent(events);
3071
3199
  clearTimeout(reqTimeout);
@@ -3098,24 +3226,39 @@ var Commands = class {
3098
3226
  `Sandbox envd version ${this.envdVersion} can't specify stdin, it's always turned on. Please rebuild your template if you need this feature.`
3099
3227
  );
3100
3228
  }
3101
- const events = this.rpc.start(
3102
- {
3103
- process: {
3104
- cmd: "/bin/bash",
3105
- cwd: opts == null ? void 0 : opts.cwd,
3106
- envs: opts == null ? void 0 : opts.envs,
3107
- args: ["-l", "-c", cmd]
3108
- },
3109
- stdin: (opts == null ? void 0 : opts.stdin) || false
3229
+ const resume = this.supportsProcessResume;
3230
+ const request = {
3231
+ process: {
3232
+ cmd: "/bin/bash",
3233
+ cwd: opts == null ? void 0 : opts.cwd,
3234
+ envs: opts == null ? void 0 : opts.envs,
3235
+ args: ["-l", "-c", cmd]
3110
3236
  },
3111
- {
3112
- headers: __spreadProps(__spreadValues({}, authenticationHeader(this.envdVersion, opts == null ? void 0 : opts.user)), {
3113
- [KEEPALIVE_PING_HEADER]: KEEPALIVE_PING_INTERVAL_SEC.toString()
3114
- }),
3115
- signal: controller.signal,
3116
- timeoutMs: (_b = opts == null ? void 0 : opts.timeoutMs) != null ? _b : this.defaultProcessConnectionTimeout
3117
- }
3118
- );
3237
+ stdin: (opts == null ? void 0 : opts.stdin) || false,
3238
+ // A retried start with the same key attaches to the first one.
3239
+ idempotencyKey: resume ? crypto.randomUUID() : void 0
3240
+ };
3241
+ const timeoutMs = (_b = opts == null ? void 0 : opts.timeoutMs) != null ? _b : this.defaultProcessConnectionTimeout;
3242
+ const deadline = timeoutMs ? Date.now() + timeoutMs : void 0;
3243
+ const callOptions = (remaining) => ({
3244
+ headers: __spreadProps(__spreadValues({}, authenticationHeader(this.envdVersion, opts == null ? void 0 : opts.user)), {
3245
+ [KEEPALIVE_PING_HEADER]: KEEPALIVE_PING_INTERVAL_SEC.toString()
3246
+ }),
3247
+ signal: controller.signal,
3248
+ timeoutMs: remaining
3249
+ });
3250
+ const started = this.rpc.start(request, callOptions(timeoutMs));
3251
+ const events = resume ? resumableProcessEvents(
3252
+ started,
3253
+ (pid, afterSequence) => pid === void 0 ? this.rpc.start(request, callOptions(remainingMs(deadline))) : this.rpc.connect(
3254
+ {
3255
+ process: { selector: { case: "pid", value: pid } },
3256
+ afterSequence
3257
+ },
3258
+ callOptions(remainingMs(deadline))
3259
+ ),
3260
+ { signal: controller.signal, logger: this.connectionConfig.logger }
3261
+ ) : started;
3119
3262
  try {
3120
3263
  const pid = await handleProcessStartEvent(events);
3121
3264
  clearTimeout(reqTimeout);