@boxes-dev/dvb 1.0.94 → 1.0.96

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/bin/dvb.cjs CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  "use strict";
3
- !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="26ee0fe3-516b-5946-82b2-f97da351c971")}catch(e){}}();
3
+ !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="5309eb3b-ad7d-544a-ac38-27de2de7afe5")}catch(e){}}();
4
4
 
5
5
  var __create = Object.create;
6
6
  var __defProp = Object.defineProperty;
@@ -88688,8 +88688,8 @@ var init_otel = __esm({
88688
88688
  return trimmed && trimmed.length > 0 ? trimmed : void 0;
88689
88689
  };
88690
88690
  readBuildMetadata = () => {
88691
- const rawPackageVersion = "1.0.94";
88692
- const rawGitSha = "a8b68f87f77be11bf168eddd6c7102a54fba377d";
88691
+ const rawPackageVersion = "1.0.96";
88692
+ const rawGitSha = "03fdc68d52f28caed613d1b095404cdf4317cb2f";
88693
88693
  const packageVersion = typeof rawPackageVersion === "string" ? rawPackageVersion : void 0;
88694
88694
  const gitSha = typeof rawGitSha === "string" ? rawGitSha : void 0;
88695
88695
  return { packageVersion, gitSha };
@@ -120679,9 +120679,9 @@ var init_sentry = __esm({
120679
120679
  sentryEnabled = false;
120680
120680
  uncaughtExceptionMonitorInstalled = false;
120681
120681
  readBuildMetadata2 = () => {
120682
- const rawPackageVersion = "1.0.94";
120683
- const rawGitSha = "a8b68f87f77be11bf168eddd6c7102a54fba377d";
120684
- const rawSentryRelease = "boxes-dev-dvb@1.0.94+a8b68f87f77be11bf168eddd6c7102a54fba377d";
120682
+ const rawPackageVersion = "1.0.96";
120683
+ const rawGitSha = "03fdc68d52f28caed613d1b095404cdf4317cb2f";
120684
+ const rawSentryRelease = "boxes-dev-dvb@1.0.96+03fdc68d52f28caed613d1b095404cdf4317cb2f";
120685
120685
  const packageVersion = typeof rawPackageVersion === "string" ? rawPackageVersion : void 0;
120686
120686
  const gitSha = typeof rawGitSha === "string" ? rawGitSha : void 0;
120687
120687
  const sentryRelease = typeof rawSentryRelease === "string" ? rawSentryRelease : void 0;
@@ -137178,7 +137178,7 @@ var init_controlPlane = __esm({
137178
137178
  });
137179
137179
 
137180
137180
  // src/devbox/daemonClient.ts
137181
- var import_node_http3, import_node_module2, import_node_path10, import_node_child_process3, import_node_crypto7, import_node_fs5, import_promises6, DAEMON_TIMEOUT_MS, AUTH_RELOGIN_HINT, readNonEmptyString, extractDaemonErrorPayload, shouldAttachReloginHint, formatDaemonResponseError, throwDaemonResponseError, DaemonConnectionError, isConnectionError, unixSocketPathLimit, isSocketPathTooLong, expectedDaemonVersionCache, daemonFeaturesCache, readExpectedDaemonVersion, normalizeVersion, requestJson3, requireDaemonFeatures, resolveDaemonCommand, spawnDaemon, waitForHealth, listAlternateSocketPaths, pruneDuplicateDaemons, listDaemonPidsForSocket, pruneSameSocketDaemons, maybeRestartDaemonForVersionMismatch, ensureDaemonRunning, ensureDaemonUpToDateIfRunning, waitForSocketGone, stopDaemon;
137181
+ var import_node_http3, import_node_module2, import_node_path10, import_node_child_process3, import_node_crypto7, import_node_fs5, import_promises6, DAEMON_TIMEOUT_MS, AUTH_RELOGIN_HINT, readNonEmptyString, extractDaemonErrorPayload, shouldAttachReloginHint, formatDaemonResponseError, throwDaemonResponseError, DaemonConnectionError, isConnectionError, unixSocketPathLimit, isSocketPathTooLong, expectedDaemonVersionCache, daemonFeaturesCache, ensureDaemonRunningInFlight, readExpectedDaemonVersion, normalizeVersion, requestJson3, requireDaemonFeatures, resolveDaemonCommand, spawnDaemon, waitForHealth, listAlternateSocketPaths, pruneDuplicateDaemons, listDaemonPidsForSocket, pruneSameSocketDaemons, maybeRestartDaemonForVersionMismatch, readHealthyDaemon, ensureDaemonRunning, ensureDaemonUpToDateIfRunning, waitForSocketGone, stopDaemon;
137182
137182
  var init_daemonClient = __esm({
137183
137183
  "src/devbox/daemonClient.ts"() {
137184
137184
  "use strict";
@@ -137260,6 +137260,7 @@ var init_daemonClient = __esm({
137260
137260
  };
137261
137261
  expectedDaemonVersionCache = null;
137262
137262
  daemonFeaturesCache = /* @__PURE__ */ new Map();
137263
+ ensureDaemonRunningInFlight = /* @__PURE__ */ new Map();
137263
137264
  readExpectedDaemonVersion = () => {
137264
137265
  if (expectedDaemonVersionCache) return expectedDaemonVersionCache;
137265
137266
  const base = (() => {
@@ -137592,53 +137593,78 @@ var init_daemonClient = __esm({
137592
137593
  spawnDaemon(socketPath);
137593
137594
  return await waitForHealth(socketPath, 5e3);
137594
137595
  };
137595
- ensureDaemonRunning = async (socketPath) => {
137596
- daemonFeaturesCache.delete(socketPath);
137596
+ readHealthyDaemon = async (socketPath, timeoutMs) => {
137597
137597
  try {
137598
137598
  const response = await requestJson3(
137599
137599
  socketPath,
137600
137600
  "GET",
137601
137601
  "/health",
137602
- DAEMON_TIMEOUT_MS.health
137602
+ timeoutMs
137603
137603
  );
137604
137604
  if (response.status === 200 && response.body.ok) {
137605
+ return response.body;
137606
+ }
137607
+ } catch (error2) {
137608
+ if (!isConnectionError(error2)) throw error2;
137609
+ }
137610
+ return null;
137611
+ };
137612
+ ensureDaemonRunning = async (socketPath) => {
137613
+ const inFlight = ensureDaemonRunningInFlight.get(socketPath);
137614
+ if (inFlight) {
137615
+ return await inFlight;
137616
+ }
137617
+ const ensure = (async () => {
137618
+ daemonFeaturesCache.delete(socketPath);
137619
+ const active = await readHealthyDaemon(
137620
+ socketPath,
137621
+ DAEMON_TIMEOUT_MS.health
137622
+ );
137623
+ if (active) {
137605
137624
  await pruneDuplicateDaemons(socketPath);
137606
137625
  const health2 = await maybeRestartDaemonForVersionMismatch(
137607
137626
  socketPath,
137608
- response.body
137627
+ active
137609
137628
  );
137610
137629
  pruneSameSocketDaemons(socketPath, health2.pid);
137611
137630
  return health2;
137612
137631
  }
137613
- } catch (error2) {
137614
- if (!isConnectionError(error2)) throw error2;
137632
+ await pruneDuplicateDaemons(socketPath);
137633
+ try {
137634
+ const recovered = await waitForHealth(socketPath, 1200);
137635
+ const health2 = await maybeRestartDaemonForVersionMismatch(
137636
+ socketPath,
137637
+ recovered
137638
+ );
137639
+ pruneSameSocketDaemons(socketPath, health2.pid);
137640
+ return health2;
137641
+ } catch {
137642
+ }
137643
+ spawnDaemon(socketPath);
137644
+ const health = await waitForHealth(socketPath, 5e3);
137645
+ pruneSameSocketDaemons(socketPath, health.pid);
137646
+ return health;
137647
+ })();
137648
+ ensureDaemonRunningInFlight.set(socketPath, ensure);
137649
+ try {
137650
+ return await ensure;
137651
+ } finally {
137652
+ if (ensureDaemonRunningInFlight.get(socketPath) === ensure) {
137653
+ ensureDaemonRunningInFlight.delete(socketPath);
137654
+ }
137615
137655
  }
137616
- await pruneDuplicateDaemons(socketPath);
137617
- spawnDaemon(socketPath);
137618
- const health = await waitForHealth(socketPath, 5e3);
137619
- pruneSameSocketDaemons(socketPath, health.pid);
137620
- return health;
137621
137656
  };
137622
137657
  ensureDaemonUpToDateIfRunning = async (socketPath) => {
137623
137658
  daemonFeaturesCache.delete(socketPath);
137624
- try {
137625
- const response = await requestJson3(
137659
+ const active = await readHealthyDaemon(socketPath, DAEMON_TIMEOUT_MS.health);
137660
+ if (active) {
137661
+ await pruneDuplicateDaemons(socketPath);
137662
+ const health = await maybeRestartDaemonForVersionMismatch(
137626
137663
  socketPath,
137627
- "GET",
137628
- "/health",
137629
- DAEMON_TIMEOUT_MS.health
137664
+ active
137630
137665
  );
137631
- if (response.status === 200 && response.body.ok) {
137632
- await pruneDuplicateDaemons(socketPath);
137633
- const health = await maybeRestartDaemonForVersionMismatch(
137634
- socketPath,
137635
- response.body
137636
- );
137637
- pruneSameSocketDaemons(socketPath, health.pid);
137638
- return health;
137639
- }
137640
- } catch (error2) {
137641
- if (!isConnectionError(error2)) throw error2;
137666
+ pruneSameSocketDaemons(socketPath, health.pid);
137667
+ return health;
137642
137668
  }
137643
137669
  return null;
137644
137670
  };
@@ -138164,6 +138190,864 @@ var init_osc = __esm({
138164
138190
  }
138165
138191
  });
138166
138192
 
138193
+ // src/devbox/terminal/sessionProtocol.ts
138194
+ var HEARTBEAT_INTERVAL_MS, INPUT_PROBE_TIMEOUT_MS, STREAM_STALL_PROBE_MISS_THRESHOLD, CONNECT_OPEN_TIMEOUT_MS, WS_OPEN_STATE, MODAL_DISCONNECT_FILTER_CHUNKS, createScrollbackEraseFilter, createInitialAttachClearFilter, createModalTtyOutputFilter, stripModalDisconnectArtifacts, streamExecSession;
138195
+ var init_sessionProtocol = __esm({
138196
+ "src/devbox/terminal/sessionProtocol.ts"() {
138197
+ "use strict";
138198
+ init_logger3();
138199
+ init_osc();
138200
+ HEARTBEAT_INTERVAL_MS = 4e3;
138201
+ INPUT_PROBE_TIMEOUT_MS = 1e3;
138202
+ STREAM_STALL_PROBE_MISS_THRESHOLD = 2;
138203
+ CONNECT_OPEN_TIMEOUT_MS = 2e4;
138204
+ WS_OPEN_STATE = 1;
138205
+ MODAL_DISCONNECT_FILTER_CHUNKS = 8;
138206
+ createScrollbackEraseFilter = () => {
138207
+ let state = 0;
138208
+ const flushPending = (output) => {
138209
+ if (state === 1) {
138210
+ output.push(27);
138211
+ } else if (state === 2) {
138212
+ output.push(27, 91);
138213
+ } else if (state === 3) {
138214
+ output.push(27, 91, 51);
138215
+ } else if (state === 10) {
138216
+ output.push(155);
138217
+ } else if (state === 11) {
138218
+ output.push(155, 51);
138219
+ }
138220
+ state = 0;
138221
+ };
138222
+ const pushByte = (output, byte) => {
138223
+ if (state === 0) {
138224
+ if (byte === 27) {
138225
+ state = 1;
138226
+ return;
138227
+ }
138228
+ if (byte === 155) {
138229
+ state = 10;
138230
+ return;
138231
+ }
138232
+ output.push(byte);
138233
+ return;
138234
+ }
138235
+ if (state === 1) {
138236
+ if (byte === 91) {
138237
+ state = 2;
138238
+ return;
138239
+ }
138240
+ output.push(27);
138241
+ state = 0;
138242
+ pushByte(output, byte);
138243
+ return;
138244
+ }
138245
+ if (state === 2) {
138246
+ if (byte === 51) {
138247
+ state = 3;
138248
+ return;
138249
+ }
138250
+ output.push(27, 91);
138251
+ state = 0;
138252
+ pushByte(output, byte);
138253
+ return;
138254
+ }
138255
+ if (state === 3) {
138256
+ if (byte === 74) {
138257
+ state = 0;
138258
+ return;
138259
+ }
138260
+ output.push(27, 91, 51);
138261
+ state = 0;
138262
+ pushByte(output, byte);
138263
+ return;
138264
+ }
138265
+ if (state === 10) {
138266
+ if (byte === 51) {
138267
+ state = 11;
138268
+ return;
138269
+ }
138270
+ output.push(155);
138271
+ state = 0;
138272
+ pushByte(output, byte);
138273
+ return;
138274
+ }
138275
+ if (state === 11) {
138276
+ if (byte === 74) {
138277
+ state = 0;
138278
+ return;
138279
+ }
138280
+ output.push(155, 51);
138281
+ state = 0;
138282
+ pushByte(output, byte);
138283
+ }
138284
+ };
138285
+ return {
138286
+ reset() {
138287
+ state = 0;
138288
+ },
138289
+ transform(chunk) {
138290
+ const bytes = Buffer.from(chunk ?? Buffer.alloc(0));
138291
+ if (bytes.length === 0) {
138292
+ return bytes;
138293
+ }
138294
+ const output = [];
138295
+ for (const byte of bytes) {
138296
+ pushByte(output, byte);
138297
+ }
138298
+ return output.length === 0 ? Buffer.alloc(0) : Buffer.from(output);
138299
+ },
138300
+ flush() {
138301
+ const output = [];
138302
+ flushPending(output);
138303
+ return output.length === 0 ? Buffer.alloc(0) : Buffer.from(output);
138304
+ }
138305
+ };
138306
+ };
138307
+ createInitialAttachClearFilter = () => {
138308
+ const patterns = [
138309
+ Buffer.from("\x1B[H\x1B[J", "latin1"),
138310
+ Buffer.from("\x1B[H\x1B[2J", "latin1"),
138311
+ Buffer.from("\x1B[2J\x1B[H", "latin1"),
138312
+ Buffer.from("\x1B[H", "latin1"),
138313
+ Buffer.from("\x1B[2J", "latin1"),
138314
+ Buffer.from("\x1B[J", "latin1"),
138315
+ Buffer.from("\x1B[?1049h", "latin1"),
138316
+ Buffer.from("\x1B[?1048h", "latin1"),
138317
+ Buffer.from("\x1B[?1047h", "latin1"),
138318
+ Buffer.from("\x1B[?47h", "latin1"),
138319
+ Buffer.from("\x1B[?1h", "latin1"),
138320
+ Buffer.from("\x1B=", "latin1"),
138321
+ Buffer.from("\x9BH", "latin1"),
138322
+ Buffer.from("\x9B2J", "latin1"),
138323
+ Buffer.from("\x9BJ", "latin1"),
138324
+ Buffer.from("\x9B?1049h", "latin1"),
138325
+ Buffer.from("\x9B?1048h", "latin1"),
138326
+ Buffer.from("\x9B?1047h", "latin1"),
138327
+ Buffer.from("\x9B?47h", "latin1"),
138328
+ Buffer.from("\x9B?1h", "latin1")
138329
+ ];
138330
+ const maxPatternLength = patterns.reduce(
138331
+ (max, pattern) => Math.max(max, pattern.length),
138332
+ 0
138333
+ );
138334
+ const STARTUP_FILTER_CHUNKS = 6;
138335
+ let enabled = true;
138336
+ let pending = Buffer.alloc(0);
138337
+ let chunksRemaining = STARTUP_FILTER_CHUNKS;
138338
+ const startsWithPatternPrefix = (bytes) => patterns.some((pattern) => {
138339
+ if (bytes.length > pattern.length) {
138340
+ return false;
138341
+ }
138342
+ return pattern.subarray(0, bytes.length).equals(bytes);
138343
+ });
138344
+ const stripLeadingPatterns = (bytes) => {
138345
+ let remaining = bytes;
138346
+ let removed = true;
138347
+ while (removed && remaining.length > 0) {
138348
+ removed = false;
138349
+ for (const pattern of patterns) {
138350
+ if (remaining.length >= pattern.length) {
138351
+ const candidate = remaining.subarray(0, pattern.length);
138352
+ if (candidate.equals(pattern)) {
138353
+ remaining = remaining.subarray(pattern.length);
138354
+ removed = true;
138355
+ break;
138356
+ }
138357
+ }
138358
+ }
138359
+ }
138360
+ return remaining;
138361
+ };
138362
+ const stripInlineArtifacts = (bytes) => {
138363
+ if (bytes.length === 0) return bytes;
138364
+ let text = bytes.toString("latin1");
138365
+ text = text.replace(/\x1b\[[0-9;]*H/g, "\r");
138366
+ text = text.replace(/\x9b[0-9;]*H/g, "\r");
138367
+ text = text.replace(
138368
+ /\x1b\]([^\x07\x1b]*)(\x07|\x1b\\)/g,
138369
+ (match2, payload) => payload.startsWith(BROWSER_OPEN_OSC_PREFIX) ? match2 : ""
138370
+ );
138371
+ const artifactPatterns = [
138372
+ /\x01/g,
138373
+ /\x1b\[\?1049h/g,
138374
+ /\x1b\[\?1048h/g,
138375
+ /\x1b\[\?1047h/g,
138376
+ /\x1b\[\?47h/g,
138377
+ /\x1b\[\?1h/g,
138378
+ /\x1b\[\?2004h/g,
138379
+ /\x1b=/g,
138380
+ /\x9b\?1049h/g,
138381
+ /\x9b\?1048h/g,
138382
+ /\x9b\?1047h/g,
138383
+ /\x9b\?47h/g,
138384
+ /\x9b\?1h/g,
138385
+ /\x9b\?2004h/g,
138386
+ /\x1b\[[0-9;?]*J/g,
138387
+ /\x9b[0-9;?]*J/g
138388
+ ];
138389
+ for (const pattern of artifactPatterns) {
138390
+ text = text.replace(pattern, "");
138391
+ }
138392
+ text = text.replace(/\r{2,}/g, "\r");
138393
+ if (/^\r+$/.test(text)) {
138394
+ return Buffer.alloc(0);
138395
+ }
138396
+ return Buffer.from(text, "latin1");
138397
+ };
138398
+ return {
138399
+ reset() {
138400
+ enabled = true;
138401
+ pending = Buffer.alloc(0);
138402
+ chunksRemaining = STARTUP_FILTER_CHUNKS;
138403
+ },
138404
+ transform(chunk) {
138405
+ const bytes = Buffer.from(chunk ?? Buffer.alloc(0));
138406
+ if (bytes.length === 0) {
138407
+ return bytes;
138408
+ }
138409
+ if (!enabled) {
138410
+ return bytes;
138411
+ }
138412
+ let work = pending.length > 0 ? Buffer.concat([pending, bytes]) : Buffer.from(bytes);
138413
+ pending = Buffer.alloc(0);
138414
+ work = stripLeadingPatterns(work);
138415
+ work = stripInlineArtifacts(work);
138416
+ chunksRemaining = Math.max(0, chunksRemaining - 1);
138417
+ if (work.length === 0) {
138418
+ if (chunksRemaining === 0) {
138419
+ enabled = false;
138420
+ }
138421
+ return Buffer.alloc(0);
138422
+ }
138423
+ const holdBytes = Math.min(
138424
+ work.length,
138425
+ Math.max(1, maxPatternLength - 1)
138426
+ );
138427
+ if (holdBytes > 0) {
138428
+ const prefix = work.subarray(0, holdBytes);
138429
+ if (prefix.length === work.length && startsWithPatternPrefix(prefix)) {
138430
+ pending = Buffer.from(prefix);
138431
+ return Buffer.alloc(0);
138432
+ }
138433
+ }
138434
+ if (chunksRemaining === 0) {
138435
+ enabled = false;
138436
+ }
138437
+ return work;
138438
+ },
138439
+ flush() {
138440
+ const out = pending;
138441
+ pending = Buffer.alloc(0);
138442
+ enabled = false;
138443
+ chunksRemaining = 0;
138444
+ return out;
138445
+ }
138446
+ };
138447
+ };
138448
+ createModalTtyOutputFilter = () => {
138449
+ const initialAttachClearFilter = createInitialAttachClearFilter();
138450
+ const scrollbackEraseFilter = createScrollbackEraseFilter();
138451
+ return {
138452
+ reset() {
138453
+ initialAttachClearFilter.reset?.();
138454
+ scrollbackEraseFilter.reset?.();
138455
+ },
138456
+ transform(chunk) {
138457
+ const initialFiltered = initialAttachClearFilter.transform(chunk);
138458
+ if (initialFiltered.length === 0) {
138459
+ return Buffer.alloc(0);
138460
+ }
138461
+ return scrollbackEraseFilter.transform(initialFiltered);
138462
+ },
138463
+ flush() {
138464
+ const pendingInitial = initialAttachClearFilter.flush();
138465
+ const pendingFiltered = pendingInitial.length > 0 ? scrollbackEraseFilter.transform(pendingInitial) : Buffer.alloc(0);
138466
+ const pendingScrollback = scrollbackEraseFilter.flush();
138467
+ if (pendingFiltered.length === 0) {
138468
+ return pendingScrollback;
138469
+ }
138470
+ if (pendingScrollback.length === 0) {
138471
+ return pendingFiltered;
138472
+ }
138473
+ return Buffer.concat([pendingFiltered, pendingScrollback]);
138474
+ }
138475
+ };
138476
+ };
138477
+ stripModalDisconnectArtifacts = (chunk) => {
138478
+ if (chunk.length === 0) return chunk;
138479
+ let text = chunk.toString("latin1");
138480
+ const artifactPatterns = [
138481
+ /\x01/g,
138482
+ /\x03\x00/g,
138483
+ /\x1b\[\?1000l/g,
138484
+ /\x1b\[\?1002l/g,
138485
+ /\x1b\[\?1003l/g,
138486
+ /\x1b\[\?1004l/g,
138487
+ /\x1b\[\?1005l/g,
138488
+ /\x1b\[\?1006l/g,
138489
+ /\x1b\[\?2004l/g,
138490
+ /\x1b\[\?1049l/g,
138491
+ /\x1b\[\?1048l/g,
138492
+ /\x1b\[\?1047l/g,
138493
+ /\x1b\[\?47l/g,
138494
+ /\x1b\[\?25h/g,
138495
+ /\x1b\[<u/g,
138496
+ /\x1b\[>4;0m/g,
138497
+ /\x1b\[\?1l/g,
138498
+ /\x1b>/g
138499
+ ];
138500
+ for (const pattern of artifactPatterns) {
138501
+ text = text.replace(pattern, "");
138502
+ }
138503
+ return Buffer.from(text, "latin1");
138504
+ };
138505
+ streamExecSession = async (ws, options) => new Promise((resolve2, reject) => {
138506
+ let exitCode = null;
138507
+ let resolved = false;
138508
+ let opened = false;
138509
+ let closeCode;
138510
+ let pendingResize = null;
138511
+ let lastResize = null;
138512
+ const pendingInput = [];
138513
+ let lastSeenAt = Date.now();
138514
+ let lastStreamActivityAt = Date.now();
138515
+ let heartbeatTimer = null;
138516
+ let inputProbeTimer = null;
138517
+ let openTimer = null;
138518
+ let inputProbeStamp = 0;
138519
+ let inputProbeStreamStamp = 0;
138520
+ let streamProbeMisses = 0;
138521
+ let disconnectNoted = false;
138522
+ let errorMessage;
138523
+ const stdin = process.stdin;
138524
+ const stdout = process.stdout;
138525
+ const stderr = process.stderr;
138526
+ const latency = options.latency;
138527
+ const oscMonitor = createOscMonitor();
138528
+ const ttyOutputFilter = options.ttyOutputFilter;
138529
+ let disconnectFilterChunksRemaining = 0;
138530
+ const armDisconnectFilter = () => {
138531
+ if (!options.stripDisconnectArtifacts) return;
138532
+ disconnectFilterChunksRemaining = Math.max(
138533
+ disconnectFilterChunksRemaining,
138534
+ MODAL_DISCONNECT_FILTER_CHUNKS
138535
+ );
138536
+ };
138537
+ const applyDisconnectFilter = (chunk) => {
138538
+ if (!options.stripDisconnectArtifacts) return chunk;
138539
+ if (disconnectFilterChunksRemaining <= 0) return chunk;
138540
+ disconnectFilterChunksRemaining -= 1;
138541
+ return stripModalDisconnectArtifacts(chunk);
138542
+ };
138543
+ const initialInput = typeof options.initialInput === "string" ? Buffer.from(options.initialInput, "utf8") : options.initialInput;
138544
+ const supportsResizeControlMessages = options.supportsResizeControlMessages ?? true;
138545
+ if (options.stdin && initialInput && initialInput.length > 0) {
138546
+ pendingInput.push(initialInput);
138547
+ }
138548
+ const markAlive = () => {
138549
+ lastSeenAt = Date.now();
138550
+ };
138551
+ const markStreamAlive = () => {
138552
+ const now = Date.now();
138553
+ lastSeenAt = now;
138554
+ lastStreamActivityAt = now;
138555
+ streamProbeMisses = 0;
138556
+ };
138557
+ const noteDisconnect = () => {
138558
+ options.onDisconnectNotice?.();
138559
+ };
138560
+ const recordDisconnect = (kind) => {
138561
+ if (disconnectNoted) return;
138562
+ disconnectNoted = true;
138563
+ const details = { kind, opened };
138564
+ if (typeof closeCode === "number") {
138565
+ details.closeCode = closeCode;
138566
+ }
138567
+ latency?.noteDisconnect(details);
138568
+ };
138569
+ const finish = (code2) => {
138570
+ if (resolved) return;
138571
+ resolved = true;
138572
+ cleanup();
138573
+ resolve2({ kind: "exit", code: code2 });
138574
+ };
138575
+ const finishDetach = () => {
138576
+ if (resolved) return;
138577
+ resolved = true;
138578
+ cleanup();
138579
+ try {
138580
+ ws.close();
138581
+ } catch {
138582
+ }
138583
+ resolve2({ kind: "detach" });
138584
+ };
138585
+ const writeTtyOutput = (chunk) => {
138586
+ if (chunk.length === 0) return;
138587
+ const { output, browserUrls } = oscMonitor.write(chunk);
138588
+ if (output.length > 0) {
138589
+ stdout.write(output);
138590
+ }
138591
+ for (const url of browserUrls) {
138592
+ if (!options.openBrowser(url)) {
138593
+ stderr.write(`Failed to open browser. Visit: ${url}\r
138594
+ `);
138595
+ }
138596
+ }
138597
+ };
138598
+ const handleBinary = (buffer) => {
138599
+ if (buffer.length === 0) return;
138600
+ if (options.tty) {
138601
+ const rawBuffer = Buffer.from(buffer);
138602
+ options.onOutputChunk?.(rawBuffer);
138603
+ options.onOutput?.();
138604
+ const filteredBuffer = ttyOutputFilter ? ttyOutputFilter.transform(rawBuffer) : rawBuffer;
138605
+ writeTtyOutput(applyDisconnectFilter(filteredBuffer));
138606
+ return;
138607
+ }
138608
+ const streamId = buffer[0];
138609
+ const payload = buffer.subarray(1);
138610
+ if (streamId === 1) {
138611
+ if (payload.length > 0) {
138612
+ options.onOutputChunk?.(payload);
138613
+ }
138614
+ if (payload.length > 0) options.onOutput?.();
138615
+ stdout.write(Buffer.from(payload));
138616
+ }
138617
+ if (streamId === 2) {
138618
+ if (payload.length > 0) {
138619
+ options.onOutputChunk?.(payload);
138620
+ }
138621
+ if (payload.length > 0) options.onOutput?.();
138622
+ stderr.write(Buffer.from(payload));
138623
+ }
138624
+ if (streamId === 3 && payload.length > 0) {
138625
+ armDisconnectFilter();
138626
+ exitCode = payload[0] ?? 0;
138627
+ ws.close();
138628
+ }
138629
+ };
138630
+ const handleText = (data) => {
138631
+ try {
138632
+ const payload = JSON.parse(data);
138633
+ if (payload.type === "session_info") {
138634
+ const rawId = payload.session_id ?? payload.id ?? payload.sessionId;
138635
+ if (rawId !== void 0) {
138636
+ options.onSessionInfo?.(String(rawId));
138637
+ }
138638
+ return;
138639
+ }
138640
+ if (payload.type === "exit" && typeof payload.exit_code === "number") {
138641
+ exitCode = payload.exit_code;
138642
+ ws.close();
138643
+ return;
138644
+ }
138645
+ if (payload.type === "port_opened" || payload.type === "port_closed") {
138646
+ const port = Number(payload.port);
138647
+ if (Number.isFinite(port)) {
138648
+ const event = { type: payload.type, port };
138649
+ if (typeof payload.pid === "number") event.pid = payload.pid;
138650
+ if (typeof payload.address === "string") {
138651
+ event.address = payload.address;
138652
+ }
138653
+ options.onPortEvent?.(event);
138654
+ }
138655
+ return;
138656
+ }
138657
+ if (payload.type === "tty_replay_start") {
138658
+ options.onReplayStart?.();
138659
+ return;
138660
+ }
138661
+ if (payload.type === "tty_replay_done") {
138662
+ if (options.tty && ttyOutputFilter) {
138663
+ writeTtyOutput(applyDisconnectFilter(ttyOutputFilter.flush()));
138664
+ }
138665
+ options.onReplayDone?.();
138666
+ return;
138667
+ }
138668
+ } catch {
138669
+ }
138670
+ if (data.length > 0) {
138671
+ options.onOutputChunk?.(Buffer.from(data, "utf8"));
138672
+ }
138673
+ options.onOutput?.();
138674
+ if (options.tty) {
138675
+ if (data.includes("logout")) {
138676
+ armDisconnectFilter();
138677
+ }
138678
+ const dataBuffer = Buffer.from(data, "utf8");
138679
+ const filtered = ttyOutputFilter ? ttyOutputFilter.transform(dataBuffer) : dataBuffer;
138680
+ writeTtyOutput(applyDisconnectFilter(filtered));
138681
+ } else {
138682
+ stdout.write(data);
138683
+ }
138684
+ };
138685
+ const onMessage = (event) => {
138686
+ markStreamAlive();
138687
+ const data = event.data;
138688
+ if (typeof data === "string") {
138689
+ handleText(data);
138690
+ return;
138691
+ }
138692
+ if (data instanceof ArrayBuffer) {
138693
+ handleBinary(new Uint8Array(data));
138694
+ return;
138695
+ }
138696
+ if (data instanceof Uint8Array) {
138697
+ handleBinary(data);
138698
+ return;
138699
+ }
138700
+ if (typeof Blob !== "undefined" && data instanceof Blob) {
138701
+ data.arrayBuffer().then((buffer) => handleBinary(new Uint8Array(buffer))).catch(() => {
138702
+ });
138703
+ }
138704
+ };
138705
+ const sendResize = () => {
138706
+ if (!options.tty) return;
138707
+ if (!supportsResizeControlMessages) return;
138708
+ const { cols, rows } = options.resolveTtySize();
138709
+ if (lastResize && lastResize.cols === cols && lastResize.rows === rows) {
138710
+ return;
138711
+ }
138712
+ if (!opened) {
138713
+ pendingResize = { cols, rows };
138714
+ return;
138715
+ }
138716
+ ws.send(JSON.stringify({ type: "resize", cols, rows }));
138717
+ lastResize = { cols, rows };
138718
+ };
138719
+ const sendInput = (chunk) => {
138720
+ if (chunk.length > 0) {
138721
+ options.onInputChunk?.(chunk);
138722
+ }
138723
+ if (!latency) {
138724
+ ws.send(chunk);
138725
+ return;
138726
+ }
138727
+ const bufferedAmount = typeof ws.bufferedAmount === "number" ? ws.bufferedAmount : void 0;
138728
+ const onSent = latency.noteSend(chunk.byteLength, bufferedAmount);
138729
+ try {
138730
+ ws.send(chunk, onSent);
138731
+ } catch (error2) {
138732
+ onSent(error2 instanceof Error ? error2 : new Error(String(error2)));
138733
+ throw error2;
138734
+ }
138735
+ };
138736
+ const summarizeInputChunk = (chunk) => ({
138737
+ length: chunk.length,
138738
+ hasCtrlC: chunk.includes(3),
138739
+ hasCtrlD: chunk.includes(4),
138740
+ hasCr: chunk.includes(13),
138741
+ hasLf: chunk.includes(10)
138742
+ });
138743
+ const onStdin = (chunk) => {
138744
+ if (options.tty && options.isRawCtrlCChunk(chunk)) {
138745
+ const handled = options.onRawCtrlC?.() ?? false;
138746
+ if (handled) {
138747
+ return;
138748
+ }
138749
+ }
138750
+ if (!opened) {
138751
+ pendingInput.push(chunk);
138752
+ logger8.debug("connect_stdin_buffered_preopen", {
138753
+ ...summarizeInputChunk(chunk),
138754
+ pendingInputCount: pendingInput.length
138755
+ });
138756
+ return;
138757
+ }
138758
+ if (options.tty && chunk.length === 1 && chunk[0] === 28) {
138759
+ stderr.write("\r\nDetached.\r\n");
138760
+ logger8.info("connect_stdin_detach_key", {
138761
+ opened,
138762
+ readyState: ws.readyState
138763
+ });
138764
+ finishDetach();
138765
+ return;
138766
+ }
138767
+ if (options.tty && chunk.length === 1 && chunk[0] === 4) {
138768
+ armDisconnectFilter();
138769
+ }
138770
+ if (typeof ws.readyState === "number" && ws.readyState !== WS_OPEN_STATE) {
138771
+ logger8.warn("connect_stdin_socket_not_open", {
138772
+ readyState: ws.readyState,
138773
+ opened,
138774
+ ...summarizeInputChunk(chunk)
138775
+ });
138776
+ noteDisconnect();
138777
+ forceClose();
138778
+ onError();
138779
+ return;
138780
+ }
138781
+ const ageMs = Date.now() - lastSeenAt;
138782
+ const hasRecoveryKey = chunk.includes(3) || // Ctrl+C
138783
+ chunk.includes(4) || // Ctrl+D
138784
+ chunk.includes(13) || // Enter (CR)
138785
+ chunk.includes(10);
138786
+ if (ageMs > HEARTBEAT_INTERVAL_MS || streamProbeMisses > 0 && hasRecoveryKey) {
138787
+ startInputProbe();
138788
+ }
138789
+ if (hasRecoveryKey) {
138790
+ logger8.info("connect_stdin_recovery_key", {
138791
+ ...summarizeInputChunk(chunk),
138792
+ ageMs,
138793
+ streamProbeMisses,
138794
+ readyState: ws.readyState
138795
+ });
138796
+ }
138797
+ try {
138798
+ sendInput(chunk);
138799
+ } catch {
138800
+ logger8.warn("connect_stdin_send_failed", {
138801
+ ...summarizeInputChunk(chunk),
138802
+ ageMs,
138803
+ readyState: ws.readyState
138804
+ });
138805
+ noteDisconnect();
138806
+ forceClose();
138807
+ onError();
138808
+ }
138809
+ };
138810
+ const startInputProbe = () => {
138811
+ if (inputProbeTimer || typeof ws.ping !== "function") return;
138812
+ inputProbeStamp = lastSeenAt;
138813
+ inputProbeStreamStamp = lastStreamActivityAt;
138814
+ try {
138815
+ ws.ping?.();
138816
+ latency?.notePingSent("input_probe");
138817
+ } catch {
138818
+ }
138819
+ inputProbeTimer = setTimeout(() => {
138820
+ inputProbeTimer = null;
138821
+ if (resolved) return;
138822
+ if (lastSeenAt === inputProbeStamp) {
138823
+ streamProbeMisses = 0;
138824
+ latency?.noteInputProbeTimeout();
138825
+ noteDisconnect();
138826
+ forceClose();
138827
+ onError();
138828
+ return;
138829
+ }
138830
+ if (lastStreamActivityAt === inputProbeStreamStamp) {
138831
+ streamProbeMisses += 1;
138832
+ if (streamProbeMisses >= STREAM_STALL_PROBE_MISS_THRESHOLD) {
138833
+ latency?.noteInputProbeTimeout();
138834
+ noteDisconnect();
138835
+ forceClose();
138836
+ onError();
138837
+ }
138838
+ return;
138839
+ }
138840
+ }, INPUT_PROBE_TIMEOUT_MS);
138841
+ };
138842
+ const stopInputProbe = () => {
138843
+ if (inputProbeTimer) {
138844
+ clearTimeout(inputProbeTimer);
138845
+ inputProbeTimer = null;
138846
+ }
138847
+ };
138848
+ const stopOpenTimer = () => {
138849
+ if (openTimer) {
138850
+ clearTimeout(openTimer);
138851
+ openTimer = null;
138852
+ }
138853
+ };
138854
+ const onPong = () => {
138855
+ markAlive();
138856
+ latency?.notePong();
138857
+ };
138858
+ const forceClose = () => {
138859
+ if (typeof ws.terminate === "function") {
138860
+ ws.terminate();
138861
+ return;
138862
+ }
138863
+ ws.close();
138864
+ };
138865
+ const startHeartbeat = () => {
138866
+ if (typeof ws.ping !== "function") return;
138867
+ markAlive();
138868
+ if (typeof ws.on === "function") {
138869
+ ws.on("pong", onPong);
138870
+ }
138871
+ heartbeatTimer = setInterval(() => {
138872
+ if (resolved) return;
138873
+ try {
138874
+ ws.ping?.();
138875
+ latency?.notePingSent("heartbeat");
138876
+ } catch {
138877
+ }
138878
+ }, HEARTBEAT_INTERVAL_MS);
138879
+ };
138880
+ const stopHeartbeat = () => {
138881
+ if (heartbeatTimer) {
138882
+ clearInterval(heartbeatTimer);
138883
+ heartbeatTimer = null;
138884
+ }
138885
+ if (typeof ws.off === "function") {
138886
+ ws.off("pong", onPong);
138887
+ } else if (typeof ws.removeListener === "function") {
138888
+ ws.removeListener("pong", onPong);
138889
+ }
138890
+ };
138891
+ const startInput = () => {
138892
+ if (!options.stdin) return;
138893
+ let rawModeEnabled = false;
138894
+ if (options.tty && stdin.isTTY) {
138895
+ try {
138896
+ stdin.setRawMode(true);
138897
+ rawModeEnabled = true;
138898
+ } catch {
138899
+ logger8.warn("connect_stdin_rawmode_enable_failed");
138900
+ }
138901
+ }
138902
+ logger8.info("connect_stdin_start", {
138903
+ tty: options.tty,
138904
+ stdinIsTty: stdin.isTTY,
138905
+ rawModeEnabled
138906
+ });
138907
+ stdin.resume();
138908
+ stdin.on("data", onStdin);
138909
+ process.on("SIGWINCH", sendResize);
138910
+ };
138911
+ const stopInput = () => {
138912
+ if (!options.stdin) return;
138913
+ stdin.removeListener("data", onStdin);
138914
+ process.removeListener("SIGWINCH", sendResize);
138915
+ stdin.pause();
138916
+ let rawModeRestored = false;
138917
+ if (options.tty && stdin.isTTY) {
138918
+ try {
138919
+ stdin.setRawMode(false);
138920
+ rawModeRestored = true;
138921
+ } catch {
138922
+ logger8.warn("connect_stdin_rawmode_restore_failed");
138923
+ }
138924
+ }
138925
+ logger8.info("connect_stdin_stop", {
138926
+ tty: options.tty,
138927
+ stdinIsTty: stdin.isTTY,
138928
+ rawModeRestored
138929
+ });
138930
+ };
138931
+ const flushPending = () => {
138932
+ if (!opened) return;
138933
+ if (pendingResize) {
138934
+ ws.send(
138935
+ JSON.stringify({
138936
+ type: "resize",
138937
+ cols: pendingResize.cols,
138938
+ rows: pendingResize.rows
138939
+ })
138940
+ );
138941
+ lastResize = pendingResize;
138942
+ pendingResize = null;
138943
+ }
138944
+ if (pendingInput.length > 0) {
138945
+ for (const chunk of pendingInput) {
138946
+ sendInput(chunk);
138947
+ }
138948
+ pendingInput.length = 0;
138949
+ }
138950
+ };
138951
+ const cleanup = () => {
138952
+ if (options.tty && ttyOutputFilter) {
138953
+ writeTtyOutput(ttyOutputFilter.flush());
138954
+ }
138955
+ ws.removeEventListener("message", onMessage);
138956
+ ws.removeEventListener("close", onClose);
138957
+ ws.removeEventListener("error", onError);
138958
+ ws.removeEventListener("open", onOpen);
138959
+ stopInputProbe();
138960
+ stopOpenTimer();
138961
+ stopHeartbeat();
138962
+ stopInput();
138963
+ };
138964
+ const onClose = (event) => {
138965
+ closeCode = typeof event?.code === "number" ? event.code : closeCode;
138966
+ logger8.info("connect_ws_close", {
138967
+ opened,
138968
+ closeCode,
138969
+ exitCode
138970
+ });
138971
+ recordDisconnect("close");
138972
+ if (exitCode !== null) {
138973
+ finish(exitCode);
138974
+ return;
138975
+ }
138976
+ if (closeCode === 1e3) {
138977
+ finish(0);
138978
+ return;
138979
+ }
138980
+ const result = {
138981
+ kind: "disconnect",
138982
+ opened
138983
+ };
138984
+ if (closeCode !== void 0) result.closeCode = closeCode;
138985
+ cleanup();
138986
+ resolve2(result);
138987
+ };
138988
+ const onError = (event) => {
138989
+ if (resolved) return;
138990
+ const raw = event?.data;
138991
+ if (raw instanceof Error && raw.message.trim()) {
138992
+ errorMessage = raw.message.trim();
138993
+ } else if (typeof raw === "string" && raw.trim()) {
138994
+ errorMessage = raw.trim();
138995
+ } else if (raw && typeof raw === "object" && "message" in raw && typeof raw.message === "string" && raw.message.trim()) {
138996
+ errorMessage = raw.message.trim();
138997
+ }
138998
+ recordDisconnect("error");
138999
+ const result = {
139000
+ kind: "disconnect",
139001
+ opened
139002
+ };
139003
+ if (closeCode !== void 0) result.closeCode = closeCode;
139004
+ if (errorMessage) result.errorMessage = errorMessage;
139005
+ logger8.warn("connect_ws_error", {
139006
+ opened,
139007
+ closeCode,
139008
+ errorMessage
139009
+ });
139010
+ cleanup();
139011
+ resolve2(result);
139012
+ };
139013
+ const onOpen = () => {
139014
+ stopOpenTimer();
139015
+ opened = true;
139016
+ markAlive();
139017
+ latency?.noteConnectOpen();
139018
+ logger8.info("connect_ws_open", {
139019
+ tty: options.tty,
139020
+ stdin: options.stdin
139021
+ });
139022
+ flushPending();
139023
+ startInput();
139024
+ startHeartbeat();
139025
+ options.onOpen?.();
139026
+ };
139027
+ ws.binaryType = "arraybuffer";
139028
+ ws.addEventListener("message", onMessage);
139029
+ ws.addEventListener("close", onClose);
139030
+ ws.addEventListener("error", onError);
139031
+ ws.addEventListener("open", onOpen);
139032
+ sendResize();
139033
+ const openTimeoutMs = options.openTimeoutMs ?? CONNECT_OPEN_TIMEOUT_MS;
139034
+ if (openTimeoutMs > 0) {
139035
+ openTimer = setTimeout(() => {
139036
+ if (resolved || opened) return;
139037
+ noteDisconnect();
139038
+ forceClose();
139039
+ onError({
139040
+ data: new Error(
139041
+ `Timed out waiting for session connection after ${openTimeoutMs}ms.`
139042
+ )
139043
+ });
139044
+ }, openTimeoutMs);
139045
+ openTimer.unref();
139046
+ }
139047
+ });
139048
+ }
139049
+ });
139050
+
138167
139051
  // ../../node_modules/chalk/source/vendor/ansi-styles/index.js
138168
139052
  function assembleStyles() {
138169
139053
  const codes = /* @__PURE__ */ new Map();
@@ -200772,7 +201656,7 @@ var init_sessionUtils = __esm({
200772
201656
  });
200773
201657
 
200774
201658
  // src/devbox/commands/connect.ts
200775
- var import_node_child_process4, import_node_crypto10, import_node_os9, import_node_path16, import_node_readline3, import_promises13, resolveInitialSessionId, shouldAttachToExistingSession, resolveSessionSpecifierFromExplicitTarget, isAttachReplacedCloseCode, shouldCancelConnectOnSigint, isRawCtrlCChunk, DEFAULT_TTY_COLS, DEFAULT_TTY_ROWS, TERMINAL_INPUT_MODE_RESET, resetTerminalInputModes, openBrowser2, warnSetupStatus, resolveTtyEnv, formatEnvExports, buildModalInteractiveCommand, parseEnvSize, readStreamSize, resolveTtySize, resolveSessionEnv, parseReachabilityState, runCommand, checkReachability, watchReachabilityWithScutil, watchReachabilityWithNotifyutil, waitForNetworkOnline, parseConnectArgs, parseConnectTarget, isSessionNotFoundError, SESSION_NAME_TOKEN_KEY, encodeSessionNameToken, decodeSessionNameToken, extractSessionNameFromCommand, SESSION_LOG_FLUSH_BYTES, SESSION_LOG_EOF_MARKER, createRemoteSessionLogSink, CONNECT_SHELL_CANDIDATES, resolveConnectShell, confirmNewSession, promptRenameSession, HEARTBEAT_INTERVAL_MS, INPUT_PROBE_TIMEOUT_MS, STREAM_STALL_PROBE_MISS_THRESHOLD, CONNECT_OPEN_TIMEOUT_MS, WS_OPEN_STATE, createScrollbackEraseFilter, createInitialAttachClearFilter, createModalTtyOutputFilter, MODAL_DISCONNECT_FILTER_CHUNKS, stripModalDisconnectArtifacts, streamExecSession, runConnect;
201659
+ var import_node_child_process4, import_node_crypto10, import_node_os9, import_node_path16, import_node_readline3, import_promises13, resolveInitialSessionId, shouldAttachToExistingSession, resolveSessionSpecifierFromExplicitTarget, isAttachReplacedCloseCode, shouldCancelConnectOnSigint, isRawCtrlCChunk, DEFAULT_TTY_COLS, DEFAULT_TTY_ROWS, TERMINAL_INPUT_MODE_RESET, resetTerminalInputModes, openBrowser2, warnSetupStatus, resolveTtyEnv, formatEnvExports, buildModalInteractiveCommand, parseEnvSize, readStreamSize, resolveTtySize, resolveSessionEnv, parseReachabilityState, runCommand, checkReachability, watchReachabilityWithScutil, watchReachabilityWithNotifyutil, waitForNetworkOnline, parseConnectArgs, parseConnectTarget, isSessionNotFoundError, SESSION_NAME_TOKEN_KEY, encodeSessionNameToken, decodeSessionNameToken, extractSessionNameFromCommand, SESSION_LOG_FLUSH_BYTES, SESSION_LOG_EOF_MARKER, createRemoteSessionLogSink, CONNECT_SHELL_CANDIDATES, resolveConnectShell, confirmNewSession, promptRenameSession, CONNECT_OPEN_TIMEOUT_MS2, runConnect;
200776
201660
  var init_connect2 = __esm({
200777
201661
  "src/devbox/commands/connect.ts"() {
200778
201662
  "use strict";
@@ -200788,7 +201672,7 @@ var init_connect2 = __esm({
200788
201672
  init_auth();
200789
201673
  init_logger3();
200790
201674
  init_latency();
200791
- init_osc();
201675
+ init_sessionProtocol();
200792
201676
  init_statusLine();
200793
201677
  init_completions();
200794
201678
  init_boxSelect();
@@ -201314,854 +202198,7 @@ var init_connect2 = __esm({
201314
202198
  const trimmed = answer.trim();
201315
202199
  return trimmed.length ? trimmed : null;
201316
202200
  };
201317
- HEARTBEAT_INTERVAL_MS = 4e3;
201318
- INPUT_PROBE_TIMEOUT_MS = 1e3;
201319
- STREAM_STALL_PROBE_MISS_THRESHOLD = 2;
201320
- CONNECT_OPEN_TIMEOUT_MS = 2e4;
201321
- WS_OPEN_STATE = 1;
201322
- createScrollbackEraseFilter = () => {
201323
- let state = 0;
201324
- const flushPending = (output) => {
201325
- if (state === 1) {
201326
- output.push(27);
201327
- } else if (state === 2) {
201328
- output.push(27, 91);
201329
- } else if (state === 3) {
201330
- output.push(27, 91, 51);
201331
- } else if (state === 10) {
201332
- output.push(155);
201333
- } else if (state === 11) {
201334
- output.push(155, 51);
201335
- }
201336
- state = 0;
201337
- };
201338
- const pushByte = (output, byte) => {
201339
- if (state === 0) {
201340
- if (byte === 27) {
201341
- state = 1;
201342
- return;
201343
- }
201344
- if (byte === 155) {
201345
- state = 10;
201346
- return;
201347
- }
201348
- output.push(byte);
201349
- return;
201350
- }
201351
- if (state === 1) {
201352
- if (byte === 91) {
201353
- state = 2;
201354
- return;
201355
- }
201356
- output.push(27);
201357
- state = 0;
201358
- pushByte(output, byte);
201359
- return;
201360
- }
201361
- if (state === 2) {
201362
- if (byte === 51) {
201363
- state = 3;
201364
- return;
201365
- }
201366
- output.push(27, 91);
201367
- state = 0;
201368
- pushByte(output, byte);
201369
- return;
201370
- }
201371
- if (state === 3) {
201372
- if (byte === 74) {
201373
- state = 0;
201374
- return;
201375
- }
201376
- output.push(27, 91, 51);
201377
- state = 0;
201378
- pushByte(output, byte);
201379
- return;
201380
- }
201381
- if (state === 10) {
201382
- if (byte === 51) {
201383
- state = 11;
201384
- return;
201385
- }
201386
- output.push(155);
201387
- state = 0;
201388
- pushByte(output, byte);
201389
- return;
201390
- }
201391
- if (state === 11) {
201392
- if (byte === 74) {
201393
- state = 0;
201394
- return;
201395
- }
201396
- output.push(155, 51);
201397
- state = 0;
201398
- pushByte(output, byte);
201399
- }
201400
- };
201401
- return {
201402
- reset() {
201403
- state = 0;
201404
- },
201405
- transform(chunk) {
201406
- const bytes = Buffer.from(chunk ?? Buffer.alloc(0));
201407
- if (bytes.length === 0) {
201408
- return bytes;
201409
- }
201410
- const output = [];
201411
- for (const byte of bytes) {
201412
- pushByte(output, byte);
201413
- }
201414
- return output.length === 0 ? Buffer.alloc(0) : Buffer.from(output);
201415
- },
201416
- flush() {
201417
- const output = [];
201418
- flushPending(output);
201419
- return output.length === 0 ? Buffer.alloc(0) : Buffer.from(output);
201420
- }
201421
- };
201422
- };
201423
- createInitialAttachClearFilter = () => {
201424
- const patterns = [
201425
- Buffer.from("\x1B[H\x1B[J", "latin1"),
201426
- Buffer.from("\x1B[H\x1B[2J", "latin1"),
201427
- Buffer.from("\x1B[2J\x1B[H", "latin1"),
201428
- Buffer.from("\x1B[H", "latin1"),
201429
- Buffer.from("\x1B[2J", "latin1"),
201430
- Buffer.from("\x1B[J", "latin1"),
201431
- Buffer.from("\x1B[?1049h", "latin1"),
201432
- Buffer.from("\x1B[?1048h", "latin1"),
201433
- Buffer.from("\x1B[?1047h", "latin1"),
201434
- Buffer.from("\x1B[?47h", "latin1"),
201435
- Buffer.from("\x1B[?1h", "latin1"),
201436
- Buffer.from("\x1B=", "latin1"),
201437
- Buffer.from("\x9BH", "latin1"),
201438
- Buffer.from("\x9B2J", "latin1"),
201439
- Buffer.from("\x9BJ", "latin1"),
201440
- Buffer.from("\x9B?1049h", "latin1"),
201441
- Buffer.from("\x9B?1048h", "latin1"),
201442
- Buffer.from("\x9B?1047h", "latin1"),
201443
- Buffer.from("\x9B?47h", "latin1"),
201444
- Buffer.from("\x9B?1h", "latin1")
201445
- ];
201446
- const maxPatternLength = patterns.reduce(
201447
- (max, pattern) => Math.max(max, pattern.length),
201448
- 0
201449
- );
201450
- const STARTUP_FILTER_CHUNKS = 6;
201451
- let enabled = true;
201452
- let pending = Buffer.alloc(0);
201453
- let chunksRemaining = STARTUP_FILTER_CHUNKS;
201454
- const startsWithPatternPrefix = (bytes) => patterns.some((pattern) => {
201455
- if (bytes.length > pattern.length) {
201456
- return false;
201457
- }
201458
- return pattern.subarray(0, bytes.length).equals(bytes);
201459
- });
201460
- const stripLeadingPatterns = (bytes) => {
201461
- let remaining = bytes;
201462
- let removed = true;
201463
- while (removed && remaining.length > 0) {
201464
- removed = false;
201465
- for (const pattern of patterns) {
201466
- if (remaining.length >= pattern.length) {
201467
- const candidate = remaining.subarray(0, pattern.length);
201468
- if (candidate.equals(pattern)) {
201469
- remaining = remaining.subarray(pattern.length);
201470
- removed = true;
201471
- break;
201472
- }
201473
- }
201474
- }
201475
- }
201476
- return remaining;
201477
- };
201478
- const stripInlineArtifacts = (bytes) => {
201479
- if (bytes.length === 0) return bytes;
201480
- let text = bytes.toString("latin1");
201481
- text = text.replace(/\x1b\[[0-9;]*H/g, "\r");
201482
- text = text.replace(/\x9b[0-9;]*H/g, "\r");
201483
- text = text.replace(
201484
- /\x1b\]([^\x07\x1b]*)(\x07|\x1b\\)/g,
201485
- (match2, payload) => payload.startsWith(BROWSER_OPEN_OSC_PREFIX) ? match2 : ""
201486
- );
201487
- const artifactPatterns = [
201488
- /\x01/g,
201489
- /\x1b\[\?1049h/g,
201490
- /\x1b\[\?1048h/g,
201491
- /\x1b\[\?1047h/g,
201492
- /\x1b\[\?47h/g,
201493
- /\x1b\[\?1h/g,
201494
- /\x1b\[\?2004h/g,
201495
- /\x1b=/g,
201496
- /\x9b\?1049h/g,
201497
- /\x9b\?1048h/g,
201498
- /\x9b\?1047h/g,
201499
- /\x9b\?47h/g,
201500
- /\x9b\?1h/g,
201501
- /\x9b\?2004h/g,
201502
- /\x1b\[[0-9;?]*J/g,
201503
- /\x9b[0-9;?]*J/g
201504
- ];
201505
- for (const pattern of artifactPatterns) {
201506
- text = text.replace(pattern, "");
201507
- }
201508
- text = text.replace(/\r{2,}/g, "\r");
201509
- if (/^\r+$/.test(text)) {
201510
- return Buffer.alloc(0);
201511
- }
201512
- return Buffer.from(text, "latin1");
201513
- };
201514
- return {
201515
- reset() {
201516
- enabled = true;
201517
- pending = Buffer.alloc(0);
201518
- chunksRemaining = STARTUP_FILTER_CHUNKS;
201519
- },
201520
- transform(chunk) {
201521
- const bytes = Buffer.from(chunk ?? Buffer.alloc(0));
201522
- if (bytes.length === 0) {
201523
- return bytes;
201524
- }
201525
- if (!enabled) {
201526
- return bytes;
201527
- }
201528
- let work = pending.length > 0 ? Buffer.concat([pending, bytes]) : Buffer.from(bytes);
201529
- pending = Buffer.alloc(0);
201530
- work = stripLeadingPatterns(work);
201531
- work = stripInlineArtifacts(work);
201532
- chunksRemaining = Math.max(0, chunksRemaining - 1);
201533
- if (work.length === 0) {
201534
- if (chunksRemaining === 0) {
201535
- enabled = false;
201536
- }
201537
- return Buffer.alloc(0);
201538
- }
201539
- const holdBytes = Math.min(
201540
- work.length,
201541
- Math.max(1, maxPatternLength - 1)
201542
- );
201543
- if (holdBytes > 0) {
201544
- const prefix = work.subarray(0, holdBytes);
201545
- if (prefix.length === work.length && startsWithPatternPrefix(prefix)) {
201546
- pending = Buffer.from(prefix);
201547
- return Buffer.alloc(0);
201548
- }
201549
- }
201550
- if (chunksRemaining === 0) {
201551
- enabled = false;
201552
- }
201553
- return work;
201554
- },
201555
- flush() {
201556
- const out = pending;
201557
- pending = Buffer.alloc(0);
201558
- enabled = false;
201559
- chunksRemaining = 0;
201560
- return out;
201561
- }
201562
- };
201563
- };
201564
- createModalTtyOutputFilter = () => {
201565
- const initialAttachClearFilter = createInitialAttachClearFilter();
201566
- const scrollbackEraseFilter = createScrollbackEraseFilter();
201567
- return {
201568
- reset() {
201569
- initialAttachClearFilter.reset?.();
201570
- scrollbackEraseFilter.reset?.();
201571
- },
201572
- transform(chunk) {
201573
- const initialFiltered = initialAttachClearFilter.transform(chunk);
201574
- if (initialFiltered.length === 0) {
201575
- return Buffer.alloc(0);
201576
- }
201577
- return scrollbackEraseFilter.transform(initialFiltered);
201578
- },
201579
- flush() {
201580
- const pendingInitial = initialAttachClearFilter.flush();
201581
- const pendingFiltered = pendingInitial.length > 0 ? scrollbackEraseFilter.transform(pendingInitial) : Buffer.alloc(0);
201582
- const pendingScrollback = scrollbackEraseFilter.flush();
201583
- if (pendingFiltered.length === 0) {
201584
- return pendingScrollback;
201585
- }
201586
- if (pendingScrollback.length === 0) {
201587
- return pendingFiltered;
201588
- }
201589
- return Buffer.concat([pendingFiltered, pendingScrollback]);
201590
- }
201591
- };
201592
- };
201593
- MODAL_DISCONNECT_FILTER_CHUNKS = 8;
201594
- stripModalDisconnectArtifacts = (chunk) => {
201595
- if (chunk.length === 0) return chunk;
201596
- let text = chunk.toString("latin1");
201597
- const artifactPatterns = [
201598
- /\x01/g,
201599
- /\x03\x00/g,
201600
- /\x1b\[\?1000l/g,
201601
- /\x1b\[\?1002l/g,
201602
- /\x1b\[\?1003l/g,
201603
- /\x1b\[\?1004l/g,
201604
- /\x1b\[\?1005l/g,
201605
- /\x1b\[\?1006l/g,
201606
- /\x1b\[\?2004l/g,
201607
- /\x1b\[\?1049l/g,
201608
- /\x1b\[\?1048l/g,
201609
- /\x1b\[\?1047l/g,
201610
- /\x1b\[\?47l/g,
201611
- /\x1b\[\?25h/g,
201612
- /\x1b\[<u/g,
201613
- /\x1b\[>4;0m/g,
201614
- /\x1b\[\?1l/g,
201615
- /\x1b>/g
201616
- ];
201617
- for (const pattern of artifactPatterns) {
201618
- text = text.replace(pattern, "");
201619
- }
201620
- return Buffer.from(text, "latin1");
201621
- };
201622
- streamExecSession = async (ws, options) => new Promise((resolve2, reject) => {
201623
- let exitCode = null;
201624
- let resolved = false;
201625
- let opened = false;
201626
- let closeCode;
201627
- let pendingResize = null;
201628
- let lastResize = null;
201629
- const pendingInput = [];
201630
- let lastSeenAt = Date.now();
201631
- let lastStreamActivityAt = Date.now();
201632
- let heartbeatTimer = null;
201633
- let inputProbeTimer = null;
201634
- let openTimer = null;
201635
- let inputProbeStamp = 0;
201636
- let inputProbeStreamStamp = 0;
201637
- let streamProbeMisses = 0;
201638
- let disconnectNoted = false;
201639
- let errorMessage;
201640
- const stdin = process.stdin;
201641
- const stdout = process.stdout;
201642
- const stderr = process.stderr;
201643
- const latency = options.latency;
201644
- const oscMonitor = createOscMonitor();
201645
- const ttyOutputFilter = options.ttyOutputFilter;
201646
- let disconnectFilterChunksRemaining = 0;
201647
- const armDisconnectFilter = () => {
201648
- if (!options.stripDisconnectArtifacts) return;
201649
- disconnectFilterChunksRemaining = Math.max(
201650
- disconnectFilterChunksRemaining,
201651
- MODAL_DISCONNECT_FILTER_CHUNKS
201652
- );
201653
- };
201654
- const applyDisconnectFilter = (chunk) => {
201655
- if (!options.stripDisconnectArtifacts) return chunk;
201656
- if (disconnectFilterChunksRemaining <= 0) return chunk;
201657
- disconnectFilterChunksRemaining -= 1;
201658
- return stripModalDisconnectArtifacts(chunk);
201659
- };
201660
- const initialInput = typeof options.initialInput === "string" ? Buffer.from(options.initialInput, "utf8") : options.initialInput;
201661
- const supportsResizeControlMessages = options.supportsResizeControlMessages ?? true;
201662
- if (options.stdin && initialInput && initialInput.length > 0) {
201663
- pendingInput.push(initialInput);
201664
- }
201665
- const markAlive = () => {
201666
- lastSeenAt = Date.now();
201667
- };
201668
- const markStreamAlive = () => {
201669
- const now = Date.now();
201670
- lastSeenAt = now;
201671
- lastStreamActivityAt = now;
201672
- streamProbeMisses = 0;
201673
- };
201674
- const noteDisconnect = () => {
201675
- options.onDisconnectNotice?.();
201676
- };
201677
- const recordDisconnect = (kind) => {
201678
- if (disconnectNoted) return;
201679
- disconnectNoted = true;
201680
- const details = { kind, opened };
201681
- if (typeof closeCode === "number") {
201682
- details.closeCode = closeCode;
201683
- }
201684
- latency?.noteDisconnect(details);
201685
- };
201686
- const finish = (code2) => {
201687
- if (resolved) return;
201688
- resolved = true;
201689
- cleanup();
201690
- resolve2({ kind: "exit", code: code2 });
201691
- };
201692
- const finishDetach = () => {
201693
- if (resolved) return;
201694
- resolved = true;
201695
- cleanup();
201696
- try {
201697
- ws.close();
201698
- } catch {
201699
- }
201700
- resolve2({ kind: "detach" });
201701
- };
201702
- const writeTtyOutput = (chunk) => {
201703
- if (chunk.length === 0) return;
201704
- const { output, browserUrls } = oscMonitor.write(chunk);
201705
- if (output.length > 0) {
201706
- stdout.write(output);
201707
- }
201708
- for (const url of browserUrls) {
201709
- if (!openBrowser2(url)) {
201710
- stderr.write(`Failed to open browser. Visit: ${url}\r
201711
- `);
201712
- }
201713
- }
201714
- };
201715
- const handleBinary = (buffer) => {
201716
- if (buffer.length === 0) return;
201717
- if (options.tty) {
201718
- const rawBuffer = Buffer.from(buffer);
201719
- options.onOutputChunk?.(rawBuffer);
201720
- options.onOutput?.();
201721
- const filteredBuffer = ttyOutputFilter ? ttyOutputFilter.transform(rawBuffer) : rawBuffer;
201722
- writeTtyOutput(applyDisconnectFilter(filteredBuffer));
201723
- return;
201724
- }
201725
- const streamId = buffer[0];
201726
- const payload = buffer.subarray(1);
201727
- if (streamId === 1) {
201728
- if (payload.length > 0) {
201729
- options.onOutputChunk?.(payload);
201730
- }
201731
- if (payload.length > 0) options.onOutput?.();
201732
- stdout.write(Buffer.from(payload));
201733
- }
201734
- if (streamId === 2) {
201735
- if (payload.length > 0) {
201736
- options.onOutputChunk?.(payload);
201737
- }
201738
- if (payload.length > 0) options.onOutput?.();
201739
- stderr.write(Buffer.from(payload));
201740
- }
201741
- if (streamId === 3 && payload.length > 0) {
201742
- armDisconnectFilter();
201743
- exitCode = payload[0] ?? 0;
201744
- ws.close();
201745
- }
201746
- };
201747
- const handleText = (data) => {
201748
- try {
201749
- const payload = JSON.parse(data);
201750
- if (payload.type === "session_info") {
201751
- const rawId = payload.session_id ?? payload.id ?? payload.sessionId;
201752
- if (rawId !== void 0) {
201753
- options.onSessionInfo?.(String(rawId));
201754
- }
201755
- return;
201756
- }
201757
- if (payload.type === "exit" && typeof payload.exit_code === "number") {
201758
- exitCode = payload.exit_code;
201759
- ws.close();
201760
- return;
201761
- }
201762
- if (payload.type === "port_opened" || payload.type === "port_closed") {
201763
- const port = Number(payload.port);
201764
- if (Number.isFinite(port)) {
201765
- const event = { type: payload.type, port };
201766
- if (typeof payload.pid === "number") event.pid = payload.pid;
201767
- if (typeof payload.address === "string") {
201768
- event.address = payload.address;
201769
- }
201770
- options.onPortEvent?.(event);
201771
- }
201772
- return;
201773
- }
201774
- if (payload.type === "tty_replay_start") {
201775
- options.onReplayStart?.();
201776
- return;
201777
- }
201778
- if (payload.type === "tty_replay_done") {
201779
- if (options.tty && ttyOutputFilter) {
201780
- writeTtyOutput(applyDisconnectFilter(ttyOutputFilter.flush()));
201781
- }
201782
- options.onReplayDone?.();
201783
- return;
201784
- }
201785
- } catch {
201786
- }
201787
- if (data.length > 0) {
201788
- options.onOutputChunk?.(Buffer.from(data, "utf8"));
201789
- }
201790
- options.onOutput?.();
201791
- if (options.tty) {
201792
- if (data.includes("logout")) {
201793
- armDisconnectFilter();
201794
- }
201795
- const dataBuffer = Buffer.from(data, "utf8");
201796
- const filtered = ttyOutputFilter ? ttyOutputFilter.transform(dataBuffer) : dataBuffer;
201797
- writeTtyOutput(applyDisconnectFilter(filtered));
201798
- } else {
201799
- stdout.write(data);
201800
- }
201801
- };
201802
- const onMessage = (event) => {
201803
- markStreamAlive();
201804
- const data = event.data;
201805
- if (typeof data === "string") {
201806
- handleText(data);
201807
- return;
201808
- }
201809
- if (data instanceof ArrayBuffer) {
201810
- handleBinary(new Uint8Array(data));
201811
- return;
201812
- }
201813
- if (data instanceof Uint8Array) {
201814
- handleBinary(data);
201815
- return;
201816
- }
201817
- if (typeof Blob !== "undefined" && data instanceof Blob) {
201818
- data.arrayBuffer().then((buffer) => handleBinary(new Uint8Array(buffer))).catch(() => {
201819
- });
201820
- }
201821
- };
201822
- const sendResize = () => {
201823
- if (!options.tty) return;
201824
- if (!supportsResizeControlMessages) return;
201825
- const { cols, rows } = resolveTtySize();
201826
- if (lastResize && lastResize.cols === cols && lastResize.rows === rows) {
201827
- return;
201828
- }
201829
- if (!opened) {
201830
- pendingResize = { cols, rows };
201831
- return;
201832
- }
201833
- ws.send(JSON.stringify({ type: "resize", cols, rows }));
201834
- lastResize = { cols, rows };
201835
- };
201836
- const sendInput = (chunk) => {
201837
- if (chunk.length > 0) {
201838
- options.onInputChunk?.(chunk);
201839
- }
201840
- if (!latency) {
201841
- ws.send(chunk);
201842
- return;
201843
- }
201844
- const bufferedAmount = typeof ws.bufferedAmount === "number" ? ws.bufferedAmount : void 0;
201845
- const onSent = latency.noteSend(chunk.byteLength, bufferedAmount);
201846
- try {
201847
- ws.send(chunk, onSent);
201848
- } catch (error2) {
201849
- onSent(error2 instanceof Error ? error2 : new Error(String(error2)));
201850
- throw error2;
201851
- }
201852
- };
201853
- const summarizeInputChunk = (chunk) => ({
201854
- length: chunk.length,
201855
- hasCtrlC: chunk.includes(3),
201856
- hasCtrlD: chunk.includes(4),
201857
- hasCr: chunk.includes(13),
201858
- hasLf: chunk.includes(10)
201859
- });
201860
- const onStdin = (chunk) => {
201861
- if (options.tty && isRawCtrlCChunk(chunk)) {
201862
- const handled = options.onRawCtrlC?.() ?? false;
201863
- if (handled) {
201864
- return;
201865
- }
201866
- }
201867
- if (!opened) {
201868
- pendingInput.push(chunk);
201869
- logger8.debug("connect_stdin_buffered_preopen", {
201870
- ...summarizeInputChunk(chunk),
201871
- pendingInputCount: pendingInput.length
201872
- });
201873
- return;
201874
- }
201875
- if (options.tty && chunk.length === 1 && chunk[0] === 28) {
201876
- stderr.write("\r\nDetached.\r\n");
201877
- logger8.info("connect_stdin_detach_key", {
201878
- opened,
201879
- readyState: ws.readyState
201880
- });
201881
- finishDetach();
201882
- return;
201883
- }
201884
- if (options.tty && chunk.length === 1 && chunk[0] === 4) {
201885
- armDisconnectFilter();
201886
- }
201887
- if (typeof ws.readyState === "number" && ws.readyState !== WS_OPEN_STATE) {
201888
- logger8.warn("connect_stdin_socket_not_open", {
201889
- readyState: ws.readyState,
201890
- opened,
201891
- ...summarizeInputChunk(chunk)
201892
- });
201893
- noteDisconnect();
201894
- forceClose();
201895
- onError();
201896
- return;
201897
- }
201898
- const ageMs = Date.now() - lastSeenAt;
201899
- const hasRecoveryKey = chunk.includes(3) || // Ctrl+C
201900
- chunk.includes(4) || // Ctrl+D
201901
- chunk.includes(13) || // Enter (CR)
201902
- chunk.includes(10);
201903
- if (ageMs > HEARTBEAT_INTERVAL_MS || streamProbeMisses > 0 && hasRecoveryKey) {
201904
- startInputProbe();
201905
- }
201906
- if (hasRecoveryKey) {
201907
- logger8.info("connect_stdin_recovery_key", {
201908
- ...summarizeInputChunk(chunk),
201909
- ageMs,
201910
- streamProbeMisses,
201911
- readyState: ws.readyState
201912
- });
201913
- }
201914
- try {
201915
- sendInput(chunk);
201916
- } catch {
201917
- logger8.warn("connect_stdin_send_failed", {
201918
- ...summarizeInputChunk(chunk),
201919
- ageMs,
201920
- readyState: ws.readyState
201921
- });
201922
- noteDisconnect();
201923
- forceClose();
201924
- onError();
201925
- }
201926
- };
201927
- const startInputProbe = () => {
201928
- if (inputProbeTimer || typeof ws.ping !== "function") return;
201929
- inputProbeStamp = lastSeenAt;
201930
- inputProbeStreamStamp = lastStreamActivityAt;
201931
- try {
201932
- ws.ping?.();
201933
- latency?.notePingSent("input_probe");
201934
- } catch {
201935
- }
201936
- inputProbeTimer = setTimeout(() => {
201937
- inputProbeTimer = null;
201938
- if (resolved) return;
201939
- if (lastSeenAt === inputProbeStamp) {
201940
- streamProbeMisses = 0;
201941
- latency?.noteInputProbeTimeout();
201942
- noteDisconnect();
201943
- forceClose();
201944
- onError();
201945
- return;
201946
- }
201947
- if (lastStreamActivityAt === inputProbeStreamStamp) {
201948
- streamProbeMisses += 1;
201949
- if (streamProbeMisses >= STREAM_STALL_PROBE_MISS_THRESHOLD) {
201950
- latency?.noteInputProbeTimeout();
201951
- noteDisconnect();
201952
- forceClose();
201953
- onError();
201954
- }
201955
- return;
201956
- }
201957
- }, INPUT_PROBE_TIMEOUT_MS);
201958
- };
201959
- const stopInputProbe = () => {
201960
- if (inputProbeTimer) {
201961
- clearTimeout(inputProbeTimer);
201962
- inputProbeTimer = null;
201963
- }
201964
- };
201965
- const stopOpenTimer = () => {
201966
- if (openTimer) {
201967
- clearTimeout(openTimer);
201968
- openTimer = null;
201969
- }
201970
- };
201971
- const onPong = () => {
201972
- markAlive();
201973
- latency?.notePong();
201974
- };
201975
- const forceClose = () => {
201976
- if (typeof ws.terminate === "function") {
201977
- ws.terminate();
201978
- return;
201979
- }
201980
- ws.close();
201981
- };
201982
- const startHeartbeat = () => {
201983
- if (typeof ws.ping !== "function") return;
201984
- markAlive();
201985
- if (typeof ws.on === "function") {
201986
- ws.on("pong", onPong);
201987
- }
201988
- heartbeatTimer = setInterval(() => {
201989
- if (resolved) return;
201990
- try {
201991
- ws.ping?.();
201992
- latency?.notePingSent("heartbeat");
201993
- } catch {
201994
- }
201995
- }, HEARTBEAT_INTERVAL_MS);
201996
- };
201997
- const stopHeartbeat = () => {
201998
- if (heartbeatTimer) {
201999
- clearInterval(heartbeatTimer);
202000
- heartbeatTimer = null;
202001
- }
202002
- if (typeof ws.off === "function") {
202003
- ws.off("pong", onPong);
202004
- } else if (typeof ws.removeListener === "function") {
202005
- ws.removeListener("pong", onPong);
202006
- }
202007
- };
202008
- const startInput = () => {
202009
- if (!options.stdin) return;
202010
- let rawModeEnabled = false;
202011
- if (options.tty && stdin.isTTY) {
202012
- try {
202013
- stdin.setRawMode(true);
202014
- rawModeEnabled = true;
202015
- } catch {
202016
- logger8.warn("connect_stdin_rawmode_enable_failed");
202017
- }
202018
- }
202019
- logger8.info("connect_stdin_start", {
202020
- tty: options.tty,
202021
- stdinIsTty: stdin.isTTY,
202022
- rawModeEnabled
202023
- });
202024
- stdin.resume();
202025
- stdin.on("data", onStdin);
202026
- process.on("SIGWINCH", sendResize);
202027
- };
202028
- const stopInput = () => {
202029
- if (!options.stdin) return;
202030
- stdin.removeListener("data", onStdin);
202031
- process.removeListener("SIGWINCH", sendResize);
202032
- stdin.pause();
202033
- let rawModeRestored = false;
202034
- if (options.tty && stdin.isTTY) {
202035
- try {
202036
- stdin.setRawMode(false);
202037
- rawModeRestored = true;
202038
- } catch {
202039
- logger8.warn("connect_stdin_rawmode_restore_failed");
202040
- }
202041
- }
202042
- logger8.info("connect_stdin_stop", {
202043
- tty: options.tty,
202044
- stdinIsTty: stdin.isTTY,
202045
- rawModeRestored
202046
- });
202047
- };
202048
- const flushPending = () => {
202049
- if (!opened) return;
202050
- if (pendingResize) {
202051
- ws.send(
202052
- JSON.stringify({
202053
- type: "resize",
202054
- cols: pendingResize.cols,
202055
- rows: pendingResize.rows
202056
- })
202057
- );
202058
- lastResize = pendingResize;
202059
- pendingResize = null;
202060
- }
202061
- if (pendingInput.length > 0) {
202062
- for (const chunk of pendingInput) {
202063
- sendInput(chunk);
202064
- }
202065
- pendingInput.length = 0;
202066
- }
202067
- };
202068
- const cleanup = () => {
202069
- if (options.tty && ttyOutputFilter) {
202070
- writeTtyOutput(ttyOutputFilter.flush());
202071
- }
202072
- ws.removeEventListener("message", onMessage);
202073
- ws.removeEventListener("close", onClose);
202074
- ws.removeEventListener("error", onError);
202075
- ws.removeEventListener("open", onOpen);
202076
- stopInputProbe();
202077
- stopOpenTimer();
202078
- stopHeartbeat();
202079
- stopInput();
202080
- };
202081
- const onClose = (event) => {
202082
- closeCode = typeof event?.code === "number" ? event.code : closeCode;
202083
- logger8.info("connect_ws_close", {
202084
- opened,
202085
- closeCode,
202086
- exitCode
202087
- });
202088
- recordDisconnect("close");
202089
- if (exitCode !== null) {
202090
- finish(exitCode);
202091
- return;
202092
- }
202093
- if (closeCode === 1e3) {
202094
- finish(0);
202095
- return;
202096
- }
202097
- const result = {
202098
- kind: "disconnect",
202099
- opened
202100
- };
202101
- if (closeCode !== void 0) result.closeCode = closeCode;
202102
- cleanup();
202103
- resolve2(result);
202104
- };
202105
- const onError = (event) => {
202106
- if (resolved) return;
202107
- const raw = event?.data;
202108
- if (raw instanceof Error && raw.message.trim()) {
202109
- errorMessage = raw.message.trim();
202110
- } else if (typeof raw === "string" && raw.trim()) {
202111
- errorMessage = raw.trim();
202112
- } else if (raw && typeof raw === "object" && "message" in raw && typeof raw.message === "string" && raw.message.trim()) {
202113
- errorMessage = raw.message.trim();
202114
- }
202115
- recordDisconnect("error");
202116
- const result = {
202117
- kind: "disconnect",
202118
- opened
202119
- };
202120
- if (closeCode !== void 0) result.closeCode = closeCode;
202121
- if (errorMessage) result.errorMessage = errorMessage;
202122
- logger8.warn("connect_ws_error", {
202123
- opened,
202124
- closeCode,
202125
- errorMessage
202126
- });
202127
- cleanup();
202128
- resolve2(result);
202129
- };
202130
- const onOpen = () => {
202131
- stopOpenTimer();
202132
- opened = true;
202133
- markAlive();
202134
- latency?.noteConnectOpen();
202135
- logger8.info("connect_ws_open", {
202136
- tty: options.tty,
202137
- stdin: options.stdin
202138
- });
202139
- flushPending();
202140
- startInput();
202141
- startHeartbeat();
202142
- options.onOpen?.();
202143
- };
202144
- ws.binaryType = "arraybuffer";
202145
- ws.addEventListener("message", onMessage);
202146
- ws.addEventListener("close", onClose);
202147
- ws.addEventListener("error", onError);
202148
- ws.addEventListener("open", onOpen);
202149
- sendResize();
202150
- const openTimeoutMs = options.openTimeoutMs ?? CONNECT_OPEN_TIMEOUT_MS;
202151
- if (openTimeoutMs > 0) {
202152
- openTimer = setTimeout(() => {
202153
- if (resolved || opened) return;
202154
- noteDisconnect();
202155
- forceClose();
202156
- onError({
202157
- data: new Error(
202158
- `Timed out waiting for session connection after ${openTimeoutMs}ms.`
202159
- )
202160
- });
202161
- }, openTimeoutMs);
202162
- openTimer.unref();
202163
- }
202164
- });
202201
+ CONNECT_OPEN_TIMEOUT_MS2 = 2e4;
202165
202202
  runConnect = async (args, overrides) => {
202166
202203
  const parsed = parseConnectArgs(args);
202167
202204
  const latency = createLatencyTracker();
@@ -202687,6 +202724,9 @@ var init_connect2 = __esm({
202687
202724
  tty: isTty,
202688
202725
  stdin: false,
202689
202726
  supportsResizeControlMessages,
202727
+ resolveTtySize,
202728
+ openBrowser: openBrowser2,
202729
+ isRawCtrlCChunk,
202690
202730
  ...computeProvider === "modal" && isTty ? (() => {
202691
202731
  const ttyOutputFilter = createModalTtyOutputFilter();
202692
202732
  return {
@@ -202867,6 +202907,9 @@ ${message}\r
202867
202907
  tty: isTty,
202868
202908
  stdin: localStdin,
202869
202909
  supportsResizeControlMessages,
202910
+ resolveTtySize,
202911
+ openBrowser: openBrowser2,
202912
+ isRawCtrlCChunk,
202870
202913
  ...computeProvider === "modal" && isTty ? (() => {
202871
202914
  const ttyOutputFilter = createModalTtyOutputFilter();
202872
202915
  return {
@@ -202875,7 +202918,7 @@ ${message}\r
202875
202918
  };
202876
202919
  })() : {},
202877
202920
  ...latency ? { latency } : {},
202878
- openTimeoutMs: CONNECT_OPEN_TIMEOUT_MS,
202921
+ openTimeoutMs: CONNECT_OPEN_TIMEOUT_MS2,
202879
202922
  onOutput: noteOutput,
202880
202923
  onOutputChunk: (chunk) => {
202881
202924
  sessionLogSink?.write(chunk);
@@ -220326,4 +220369,4 @@ smol-toml/dist/index.js:
220326
220369
  */
220327
220370
  //# sourceMappingURL=dvb.cjs.map
220328
220371
 
220329
- //# debugId=26ee0fe3-516b-5946-82b2-f97da351c971
220372
+ //# debugId=5309eb3b-ad7d-544a-ac38-27de2de7afe5