@boxes-dev/dvb 1.0.95 → 1.0.97
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 +929 -886
- package/dist/bin/dvb.cjs.map +1 -1
- package/dist/bin/dvbd.cjs +5 -5
- package/dist/devbox/commands/connect.d.ts +2 -10
- package/dist/devbox/commands/connect.d.ts.map +1 -1
- package/dist/devbox/commands/connect.js +8 -905
- package/dist/devbox/commands/connect.js.map +1 -1
- package/dist/devbox/daemonClient.d.ts.map +1 -1
- package/dist/devbox/daemonClient.js +51 -24
- package/dist/devbox/daemonClient.js.map +1 -1
- package/dist/devbox/terminal/sessionProtocol.d.ts +57 -0
- package/dist/devbox/terminal/sessionProtocol.d.ts.map +1 -0
- package/dist/devbox/terminal/sessionProtocol.js +908 -0
- package/dist/devbox/terminal/sessionProtocol.js.map +1 -0
- package/package.json +1 -1
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]="
|
|
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.
|
|
88692
|
-
const rawGitSha = "
|
|
88691
|
+
const rawPackageVersion = "1.0.97";
|
|
88692
|
+
const rawGitSha = "b188da7d76b5932bf0ca74e33fb9fa4982436b1f";
|
|
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.
|
|
120683
|
-
const rawGitSha = "
|
|
120684
|
-
const rawSentryRelease = "boxes-dev-dvb@1.0.
|
|
120682
|
+
const rawPackageVersion = "1.0.97";
|
|
120683
|
+
const rawGitSha = "b188da7d76b5932bf0ca74e33fb9fa4982436b1f";
|
|
120684
|
+
const rawSentryRelease = "boxes-dev-dvb@1.0.97+b188da7d76b5932bf0ca74e33fb9fa4982436b1f";
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
137627
|
+
active
|
|
137609
137628
|
);
|
|
137610
137629
|
pruneSameSocketDaemons(socketPath, health2.pid);
|
|
137611
137630
|
return health2;
|
|
137612
137631
|
}
|
|
137613
|
-
|
|
137614
|
-
|
|
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
|
-
|
|
137625
|
-
|
|
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
|
-
|
|
137628
|
-
"/health",
|
|
137629
|
-
DAEMON_TIMEOUT_MS.health
|
|
137664
|
+
active
|
|
137630
137665
|
);
|
|
137631
|
-
|
|
137632
|
-
|
|
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,
|
|
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
|
-
|
|
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
|
-
|
|
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:
|
|
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=
|
|
220372
|
+
//# debugId=5309eb3b-ad7d-544a-ac38-27de2de7afe5
|