tmux-ide 2.9.11 → 2.9.13
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/bin/cli.js +6036 -3047
- package/package.json +1 -1
- package/packages/contracts/src/index.ts +6 -0
- package/packages/contracts/src/pane-stream.ts +77 -0
- package/packages/contracts/src/terminal-delivery-binary-chunk.ts +55 -0
- package/packages/contracts/src/terminal-delivery.ts +19 -3
- package/packages/contracts/src/terminal-graphics-compressed.ts +66 -0
- package/packages/contracts/src/terminal-graphics.ts +73 -0
- package/packages/contracts/src/terminal-projection.ts +153 -0
- package/packages/contracts/src/terminal-surfaces.ts +137 -0
- package/packages/core/src/fixtures/terminal-projection-vectors.json +585 -0
- package/packages/core/src/index.ts +2 -0
- package/packages/core/src/terminal-delivery-binary.ts +160 -0
- package/packages/core/src/terminal-delivery.ts +377 -16
- package/packages/core/src/terminal-projection-vectors.mjs +82 -0
- package/packages/core/src/terminal-projection.ts +476 -0
- package/packages/core/src/terminal-replica.ts +34 -1
- package/packages/daemon/dist/command-center/resources/saved-machine-route.js +2 -0
- package/packages/daemon/dist/command-center/resources/saved-machine-watch.js +117 -0
- package/packages/daemon/dist/command-center/server.js +13 -0
- package/packages/daemon/dist/command-center/tmux-servers.js +9 -0
- package/packages/daemon/dist/lib/daemon-embed.js +71 -4
- package/packages/daemon/dist/lib/embedded-tmux-server-owners.js +1 -0
- package/packages/daemon/dist/lib/native-surface-context.js +96 -0
- package/packages/daemon/dist/lib/tmux-server-owner.js +10 -0
- package/packages/daemon/dist/native/TmuxIdeNotifier.app/Contents/Info.plist +2 -2
- package/packages/daemon/dist/native/TmuxIdeNotifier.app/Contents/MacOS/tmux-ide-notifier +0 -0
- package/packages/daemon/dist/native/TmuxIdeNotifier.app/Contents/Resources/Assets.car +0 -0
- package/packages/daemon/dist/native/TmuxIdeNotifier.app/Contents/_CodeSignature/CodeResources +2 -2
- package/packages/daemon/dist/server/native-surface-provider-upgrade.js +88 -0
- package/packages/daemon/dist/terminal/graphics/compress-chunk.js +40 -0
- package/packages/daemon/dist/terminal/graphics/local-image-owner.js +330 -0
- package/packages/daemon/dist/terminal/graphics/local-image-store.js +255 -0
- package/packages/daemon/dist/terminal/graphics/native-surface-demand.js +99 -0
- package/packages/daemon/dist/terminal/graphics/native-surface-provider-channel.js +162 -0
- package/packages/daemon/dist/terminal/graphics/native-surface-provider.js +275 -0
- package/packages/daemon/dist/terminal/graphics/native-surface-viewer.js +146 -0
- package/packages/daemon/dist/terminal/mirror/mirror-service.js +3 -0
- package/packages/daemon/dist/terminal/mirror/session-channel.js +32 -9
- package/packages/daemon/dist/terminal/pane-stream/pane-stream-websocket.js +369 -16
- package/packages/daemon/dist/terminal/pane-stream/runtime.js +10 -0
- package/packages/daemon/dist/terminal/session-runtime/registry.js +2 -0
- package/packages/daemon/dist/terminal/session-runtime/terminal-delivery-hub.js +146 -16
- package/packages/daemon/dist/terminal/session-runtime/terminal-projection-delivery.js +32 -0
- package/packages/daemon/dist/terminal/session-runtime/terminal-replica-owner.js +3 -4
- package/packages/daemon/dist/tui/mirror/open-tui-workspace-runtime-port.js +4 -0
- package/packages/daemon/dist/tui/mirror/runtime/application-terminal-interaction-controller.js +28 -3
- package/packages/daemon/dist/tui/mirror/runtime/application-terminal-workspace.jsx +13 -1
- package/packages/daemon/dist/tui/mirror/runtime/renderer-probe.js +195 -0
- package/packages/daemon/dist/tui/mirror/runtime/terminal-fast-lane-renderer-adapter.js +6 -0
- package/packages/daemon/dist/tui/mirror/semantic-pane-render-source.js +4 -0
- package/packages/daemon/src/command-center/resources/saved-machine-route.ts +4 -0
- package/packages/daemon/src/command-center/resources/saved-machine-watch.ts +132 -0
- package/packages/daemon/src/command-center/server.ts +18 -0
- package/packages/daemon/src/command-center/tmux-servers.ts +14 -0
- package/packages/daemon/src/lib/daemon-embed.ts +81 -3
- package/packages/daemon/src/lib/embedded-tmux-server-owners.ts +3 -0
- package/packages/daemon/src/lib/native-surface-context.ts +123 -0
- package/packages/daemon/src/lib/tmux-server-owner.ts +12 -0
- package/packages/daemon/src/server/native-surface-provider-upgrade.ts +103 -0
- package/packages/daemon/src/terminal/graphics/compress-chunk.ts +49 -0
- package/packages/daemon/src/terminal/graphics/local-image-owner.ts +346 -0
- package/packages/daemon/src/terminal/graphics/local-image-store.ts +286 -0
- package/packages/daemon/src/terminal/graphics/native-surface-demand.ts +88 -0
- package/packages/daemon/src/terminal/graphics/native-surface-provider-channel.ts +161 -0
- package/packages/daemon/src/terminal/graphics/native-surface-provider.ts +308 -0
- package/packages/daemon/src/terminal/graphics/native-surface-viewer.ts +154 -0
- package/packages/daemon/src/terminal/mirror/mirror-service.ts +5 -0
- package/packages/daemon/src/terminal/mirror/session-channel.ts +31 -10
- package/packages/daemon/src/terminal/pane-stream/pane-stream-websocket.ts +446 -15
- package/packages/daemon/src/terminal/pane-stream/runtime.ts +14 -1
- package/packages/daemon/src/terminal/session-runtime/registry.ts +2 -0
- package/packages/daemon/src/terminal/session-runtime/runtime-observability.ts +1 -1
- package/packages/daemon/src/terminal/session-runtime/terminal-delivery-hub.ts +216 -22
- package/packages/daemon/src/terminal/session-runtime/terminal-delivery-observation-identity.ts +7 -4
- package/packages/daemon/src/terminal/session-runtime/terminal-projection-delivery.ts +59 -0
- package/packages/daemon/src/terminal/session-runtime/terminal-replica-owner.ts +3 -4
- package/packages/daemon/src/tui/mirror/open-tui-workspace-runtime-port.ts +4 -0
- package/packages/daemon/src/tui/mirror/runtime/application-terminal-interaction-controller.ts +26 -4
- package/packages/daemon/src/tui/mirror/runtime/application-terminal-workspace.tsx +20 -1
- package/packages/daemon/src/tui/mirror/runtime/renderer-probe.ts +257 -0
- package/packages/daemon/src/tui/mirror/runtime/terminal-fast-lane-renderer-adapter.ts +15 -0
- package/packages/daemon/src/tui/mirror/semantic-pane-render-source.ts +4 -0
- package/packages/daemon-client/src/pane-stream-client.ts +75 -1
|
@@ -1,8 +1,12 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { TERMINAL_SURFACE_MAX_CONTROL_BYTES, TERMINAL_SURFACE_CAPABILITY_VERSION, } from "@tmux-ide/contracts";
|
|
2
|
+
import { NativeSurfaceViewer } from "../graphics/native-surface-viewer.js";
|
|
3
|
+
import { compressGraphicsChunk } from "../graphics/compress-chunk.js";
|
|
4
|
+
import { TERMINAL_GRAPHICS_COMPRESSED_CAPABILITY_VERSION, TERMINAL_GRAPHICS_COMPRESSED_LOCAL_CAPABILITY_VERSION, TERMINAL_PROJECTION_CAPABILITY_VERSION, TERMINAL_PROJECTION_LOCAL_CAPABILITY_VERSION, } from "@tmux-ide/contracts";
|
|
5
|
+
import { PANE_STREAM_INPUT_LIFETIME_CAPABILITY_VERSION, PANE_STREAM_INPUT_BYTES_CAPABILITY_VERSION, } from "@tmux-ide/contracts";
|
|
2
6
|
import { inflateSync } from "node:zlib";
|
|
3
7
|
import { PaneStreamLayoutSnapshotFrameSchemaZ } from "@tmux-ide/contracts";
|
|
4
8
|
import { z } from "zod";
|
|
5
|
-
import { PANE_STREAM_MAX_HELD_DELTAS, PANE_STREAM_MAX_OUTPUT_BYTES, PANE_STREAM_MAX_PANES, PANE_STREAM_MAX_SEED_BYTES, PANE_STREAM_PROTOCOL_VERSION, PANE_STREAM_REDEEM_PATH, PANE_STREAM_WEBSOCKET_SUBPROTOCOL, TERMINAL_GRAPHICS_BLOB_CHUNK_BYTES, TERMINAL_GRAPHICS_CELL_PIXELS_CAPABILITY_VERSION, TERMINAL_GRAPHICS_PRECISE_PIXELS_CAPABILITY_VERSION, TERMINAL_GRAPHICS_LEGACY_MAX_IMAGE_BYTES, TERMINAL_GRAPHICS_ZLIB_CAPABILITY_VERSION, PaneStreamClientFrameSchemaZ, PaneStreamLoopbackWebSocketUrlSchemaZ, PaneStreamRedeemFrameSchemaZ, PaneStreamServerFrameSchemaZ, sharedMonotonicMicros, } from "@tmux-ide/contracts";
|
|
9
|
+
import { PANE_STREAM_MAX_HELD_DELTAS, PANE_STREAM_MAX_OUTPUT_BYTES, PANE_STREAM_MAX_PANES, PANE_STREAM_MAX_SEED_BYTES, PANE_STREAM_PROTOCOL_VERSION, PANE_STREAM_REDEEM_PATH, PANE_STREAM_WEBSOCKET_SUBPROTOCOL, TERMINAL_GRAPHICS_BLOB_CHUNK_BYTES, TERMINAL_DELIVERY_BINARY_CAPABILITY_VERSION, TERMINAL_DELIVERY_BINARY_LOCAL_CAPABILITY_VERSION, TERMINAL_GRAPHICS_BINARY_CAPABILITY_VERSION, TERMINAL_GRAPHICS_LOCAL_CAPABILITY_VERSION, encodeTerminalGraphicsBinary, encodeTerminalDeliveryBinaryChunk, TERMINAL_GRAPHICS_CELL_PIXELS_CAPABILITY_VERSION, TERMINAL_GRAPHICS_PRECISE_PIXELS_CAPABILITY_VERSION, TERMINAL_GRAPHICS_LEGACY_MAX_IMAGE_BYTES, TERMINAL_GRAPHICS_ZLIB_CAPABILITY_VERSION, PaneStreamClientFrameSchemaZ, PaneStreamLoopbackWebSocketUrlSchemaZ, PaneStreamRedeemFrameSchemaZ, PaneStreamServerFrameSchemaZ, sharedMonotonicMicros, } from "@tmux-ide/contracts";
|
|
6
10
|
import { canonicalOriginOrNull, digestSecret, digestsEqual, rawDataByteLength, rawDataToBuffer, safeCloseSocket, strictJsonParse, } from "../attachments/admission-util.js";
|
|
7
11
|
import { SessionRuntimeControllerLeaseError } from "../session-runtime/registry.js";
|
|
8
12
|
import { terminalDeliveryObservationOrdinal } from "../session-runtime/terminal-delivery-observation-identity.js";
|
|
@@ -115,6 +119,8 @@ function errorFrameCode(error) {
|
|
|
115
119
|
* ticket digests; a daemon restart makes every prior descriptor inert.
|
|
116
120
|
*/
|
|
117
121
|
export class PaneStreamAdmissionCoordinator {
|
|
122
|
+
#nativeSurfaces;
|
|
123
|
+
#localImages;
|
|
118
124
|
#instanceId;
|
|
119
125
|
#webSocketUrl;
|
|
120
126
|
#leaseManager;
|
|
@@ -145,6 +151,10 @@ export class PaneStreamAdmissionCoordinator {
|
|
|
145
151
|
#shuttingDown = false;
|
|
146
152
|
#shutdownPromise = null;
|
|
147
153
|
constructor(options) {
|
|
154
|
+
this.#nativeSurfaces = options.nativeSurfaces;
|
|
155
|
+
if (this.#nativeSurfaces && this.#nativeSurfaces.generation !== options.daemonInstanceId)
|
|
156
|
+
throw new Error("Native surface provider generation mismatch");
|
|
157
|
+
this.#localImages = options.localImages;
|
|
148
158
|
this.#instanceId = BindingIdSchemaZ.parse(options.daemonInstanceId);
|
|
149
159
|
this.#webSocketUrl = PaneStreamLoopbackWebSocketUrlSchemaZ.parse(options.webSocketUrl);
|
|
150
160
|
this.#leaseManager = options.leaseManager;
|
|
@@ -407,6 +417,8 @@ export class PaneStreamAdmissionCoordinator {
|
|
|
407
417
|
let live;
|
|
408
418
|
try {
|
|
409
419
|
live = new PaneStreamLiveConnection({
|
|
420
|
+
nativeSurfaces: this.#nativeSurfaces,
|
|
421
|
+
localImages: this.#localImages,
|
|
410
422
|
clientId: `psc-${this.#clientCounter}`,
|
|
411
423
|
socket,
|
|
412
424
|
descriptor: structuredClone(descriptor),
|
|
@@ -614,6 +626,15 @@ export function rawGraphicsState(state) {
|
|
|
614
626
|
}
|
|
615
627
|
const GRAPHICS_SEND_WINDOW_BYTES = 2 * 1024 * 1024;
|
|
616
628
|
export class PaneStreamLiveConnection {
|
|
629
|
+
// One bounded native negotiation per redeemed socket; never reuse on reconnect.
|
|
630
|
+
#nativeSurfaces;
|
|
631
|
+
#surfaceViewer = null;
|
|
632
|
+
#surfaceDemands = new Map();
|
|
633
|
+
#surfaceNative = false;
|
|
634
|
+
#surfaceSession = null;
|
|
635
|
+
#surfaceReceiver = null;
|
|
636
|
+
#localImages;
|
|
637
|
+
#localLeases = new Map();
|
|
617
638
|
#clientId;
|
|
618
639
|
#socket;
|
|
619
640
|
#descriptor;
|
|
@@ -701,6 +722,8 @@ export class PaneStreamLiveConnection {
|
|
|
701
722
|
return elapsed;
|
|
702
723
|
}
|
|
703
724
|
constructor(options) {
|
|
725
|
+
this.#nativeSurfaces = options.nativeSurfaces;
|
|
726
|
+
this.#localImages = options.localImages;
|
|
704
727
|
this.#clientId = options.clientId;
|
|
705
728
|
this.#socket = options.socket;
|
|
706
729
|
this.#descriptor = options.descriptor;
|
|
@@ -770,6 +793,10 @@ export class PaneStreamLiveConnection {
|
|
|
770
793
|
this.#descriptor.terminalDelivery?.protocolVersions.includes(PANE_STREAM_INPUT_LIFETIME_CAPABILITY_VERSION)
|
|
771
794
|
? { inputLifetime: true }
|
|
772
795
|
: {}),
|
|
796
|
+
...(this.#sessionRuntimeBinding &&
|
|
797
|
+
this.#descriptor.terminalDelivery?.protocolVersions.includes(PANE_STREAM_INPUT_BYTES_CAPABILITY_VERSION)
|
|
798
|
+
? { inputBytes: true }
|
|
799
|
+
: {}),
|
|
773
800
|
protocolVersion: PANE_STREAM_PROTOCOL_VERSION,
|
|
774
801
|
daemonInstanceId: this.#binding.daemonInstanceId,
|
|
775
802
|
requestId: this.#binding.requestId,
|
|
@@ -790,6 +817,8 @@ export class PaneStreamLiveConnection {
|
|
|
790
817
|
}
|
|
791
818
|
this.#stopAuthoritySnapshots =
|
|
792
819
|
this.#sessionRuntimeBinding?.onAuthoritySnapshot?.((snapshot) => this.#usesExplicitAuthority ? this.#sendAuthoritySnapshot(snapshot) : undefined) ?? null;
|
|
820
|
+
if (!this.#descriptor.terminalDelivery)
|
|
821
|
+
this.#observeSurfaceDemand(this.#descriptor.panes);
|
|
793
822
|
void this.#subscribeAll();
|
|
794
823
|
}
|
|
795
824
|
close(code = 1000, reason = "stream-closed") {
|
|
@@ -797,6 +826,13 @@ export class PaneStreamLiveConnection {
|
|
|
797
826
|
return;
|
|
798
827
|
this.#recordDiagnosticLifecycle("pane-stream-terminal", code, reason);
|
|
799
828
|
this.#closed = true;
|
|
829
|
+
for (const demand of this.#surfaceDemands.values())
|
|
830
|
+
demand.close();
|
|
831
|
+
this.#surfaceDemands.clear();
|
|
832
|
+
this.#surfaceViewer?.close();
|
|
833
|
+
this.#surfaceViewer = null;
|
|
834
|
+
this.#surfaceSession?.close();
|
|
835
|
+
this.#surfaceSession = null;
|
|
800
836
|
this.#cancelDrainTick?.();
|
|
801
837
|
this.#cancelDrainTick = null;
|
|
802
838
|
// Departure force-returns every ticket within this same tick.
|
|
@@ -812,6 +848,12 @@ export class PaneStreamLiveConnection {
|
|
|
812
848
|
this.#stopAuthoritySnapshots?.();
|
|
813
849
|
this.#stopAuthoritySnapshots = null;
|
|
814
850
|
const closures = [];
|
|
851
|
+
this.#localLeases.clear();
|
|
852
|
+
if (this.#localImages)
|
|
853
|
+
closures.push(this.#localImages.releaseClient({
|
|
854
|
+
generation: this.#localImages.identity.generation,
|
|
855
|
+
client: this.#descriptor.leaseId,
|
|
856
|
+
}));
|
|
815
857
|
const layoutSubscription = this.#layoutSubscription;
|
|
816
858
|
this.#layoutSubscription = null;
|
|
817
859
|
if (layoutSubscription)
|
|
@@ -822,6 +864,8 @@ export class PaneStreamLiveConnection {
|
|
|
822
864
|
const delivery = channel.delivery;
|
|
823
865
|
channel.delivery = null;
|
|
824
866
|
channel.closed = true;
|
|
867
|
+
this.#surfaceDemands.get(channel.semanticPaneId)?.close();
|
|
868
|
+
this.#surfaceDemands.delete(channel.semanticPaneId);
|
|
825
869
|
if (sub)
|
|
826
870
|
closures.push(sub.close().catch(() => undefined));
|
|
827
871
|
if (delivery)
|
|
@@ -1024,7 +1068,7 @@ export class PaneStreamLiveConnection {
|
|
|
1024
1068
|
return true;
|
|
1025
1069
|
let incarnation = null;
|
|
1026
1070
|
for (const message of pending) {
|
|
1027
|
-
if (message.type !== "terminal.delivery")
|
|
1071
|
+
if (message.type !== "terminal.delivery" && message.type !== "terminal.projection")
|
|
1028
1072
|
continue;
|
|
1029
1073
|
if (message.workspaceName !== this.#descriptor.workspaceName ||
|
|
1030
1074
|
message.semanticPaneId !== channel.semanticPaneId ||
|
|
@@ -1132,7 +1176,15 @@ export class PaneStreamLiveConnection {
|
|
|
1132
1176
|
this.#closeIfAllPanesGone();
|
|
1133
1177
|
}
|
|
1134
1178
|
async #sendTerminalDelivery(pane, message) {
|
|
1135
|
-
if (message.type === "terminal.
|
|
1179
|
+
if (message.type === "terminal.projection") {
|
|
1180
|
+
const channel = this.#panes.get(pane);
|
|
1181
|
+
if (channel?.deliveryAddress)
|
|
1182
|
+
channel.deliveryAddress.incarnation = message.incarnation;
|
|
1183
|
+
if (channel)
|
|
1184
|
+
channel.binaryCells = true;
|
|
1185
|
+
this.#sendFrame(pane, { type: "terminal-projection-envelope", pane, envelope: message });
|
|
1186
|
+
}
|
|
1187
|
+
else if (message.type === "terminal.delivery") {
|
|
1136
1188
|
if (!this.#diagnosticFirstSeedObserved) {
|
|
1137
1189
|
this.#diagnosticFirstSeedObserved = true;
|
|
1138
1190
|
this.#recordDiagnosticLifecycle("pane-stream-first-seed");
|
|
@@ -1140,6 +1192,8 @@ export class PaneStreamLiveConnection {
|
|
|
1140
1192
|
const channel = this.#panes.get(pane);
|
|
1141
1193
|
if (channel?.deliveryAddress)
|
|
1142
1194
|
channel.deliveryAddress.incarnation = message.incarnation;
|
|
1195
|
+
if (channel)
|
|
1196
|
+
channel.binaryCells = message.encoding === "semantic-binary-v1";
|
|
1143
1197
|
// The trusted lease address was fixed at delivery admission; preserve the
|
|
1144
1198
|
// exact envelope and its observation identity through transmission.
|
|
1145
1199
|
const detailedDeliveryObservation = this.#observability?.enabled === true;
|
|
@@ -1215,13 +1269,18 @@ export class PaneStreamLiveConnection {
|
|
|
1215
1269
|
}
|
|
1216
1270
|
}
|
|
1217
1271
|
else if (message.type === "terminal.delivery.chunk") {
|
|
1218
|
-
this.#
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1272
|
+
if (this.#panes.get(pane)?.binaryCells) {
|
|
1273
|
+
this.#sendEncoded(pane, Buffer.from(encodeTerminalDeliveryBinaryChunk({ pane, transactionId: message.transactionId, index: message.index }, message.bytes)), true);
|
|
1274
|
+
}
|
|
1275
|
+
else {
|
|
1276
|
+
this.#sendFrame(pane, {
|
|
1277
|
+
type: "terminal-delivery-chunk",
|
|
1278
|
+
pane,
|
|
1279
|
+
transactionId: message.transactionId,
|
|
1280
|
+
index: message.index,
|
|
1281
|
+
data: Buffer.from(message.bytes).toString("base64"),
|
|
1282
|
+
});
|
|
1283
|
+
}
|
|
1225
1284
|
}
|
|
1226
1285
|
else {
|
|
1227
1286
|
this.#sendFrame(pane, { type: "terminal-delivery-fault", pane, fault: message });
|
|
@@ -1232,15 +1291,53 @@ export class PaneStreamLiveConnection {
|
|
|
1232
1291
|
}
|
|
1233
1292
|
await this.#awaitSemanticCredit(pane);
|
|
1234
1293
|
}
|
|
1294
|
+
#observeSurfaceDemand(panes) {
|
|
1295
|
+
for (const pane of panes) {
|
|
1296
|
+
if (this.#surfaceDemands.has(pane))
|
|
1297
|
+
continue;
|
|
1298
|
+
const demand = this.#nativeSurfaces?.demand.viewer(this.#descriptor.sessionName, [pane]);
|
|
1299
|
+
if (!demand)
|
|
1300
|
+
return;
|
|
1301
|
+
demand.native(this.#surfaceNative);
|
|
1302
|
+
this.#surfaceDemands.set(pane, demand);
|
|
1303
|
+
}
|
|
1304
|
+
}
|
|
1305
|
+
#surfaceControl(type) {
|
|
1306
|
+
if (type === "terminal-surface-offer")
|
|
1307
|
+
return;
|
|
1308
|
+
this.#surfaceNative = type === "terminal-surface-peer";
|
|
1309
|
+
for (const demand of this.#surfaceDemands.values())
|
|
1310
|
+
demand.native(this.#surfaceNative);
|
|
1311
|
+
}
|
|
1235
1312
|
/** Announce the pane's kitty graphics state; the client pulls bytes it lacks. */
|
|
1236
1313
|
#startGraphics(channel) {
|
|
1237
1314
|
const graphics = channel.delivery?.graphics;
|
|
1238
1315
|
if (!graphics)
|
|
1239
1316
|
return;
|
|
1317
|
+
this.#observeSurfaceDemand([channel.semanticPaneId]);
|
|
1240
1318
|
// Renderers that cannot inflate see raw formats; their bytes are inflated
|
|
1241
1319
|
// when served.
|
|
1242
1320
|
const zlib = this.#descriptor.terminalDelivery?.protocolVersions.includes(TERMINAL_GRAPHICS_ZLIB_CAPABILITY_VERSION) === true;
|
|
1243
1321
|
channel.graphicsZlib = zlib;
|
|
1322
|
+
channel.graphicsLocal =
|
|
1323
|
+
!!this.#localImages &&
|
|
1324
|
+
this.#descriptor.terminalDelivery?.protocolVersions.some((version) => version === TERMINAL_GRAPHICS_LOCAL_CAPABILITY_VERSION ||
|
|
1325
|
+
version === TERMINAL_DELIVERY_BINARY_LOCAL_CAPABILITY_VERSION ||
|
|
1326
|
+
version === TERMINAL_PROJECTION_LOCAL_CAPABILITY_VERSION ||
|
|
1327
|
+
version === TERMINAL_GRAPHICS_COMPRESSED_LOCAL_CAPABILITY_VERSION) === true;
|
|
1328
|
+
channel.graphicsCompressed =
|
|
1329
|
+
this.#descriptor.terminalDelivery?.protocolVersions.some((version) => version === TERMINAL_GRAPHICS_COMPRESSED_CAPABILITY_VERSION ||
|
|
1330
|
+
version === TERMINAL_GRAPHICS_COMPRESSED_LOCAL_CAPABILITY_VERSION) === true;
|
|
1331
|
+
channel.graphicsInline = new Set();
|
|
1332
|
+
channel.graphicsBinary =
|
|
1333
|
+
this.#descriptor.terminalDelivery?.protocolVersions.some((version) => version === TERMINAL_GRAPHICS_BINARY_CAPABILITY_VERSION ||
|
|
1334
|
+
version === TERMINAL_GRAPHICS_LOCAL_CAPABILITY_VERSION ||
|
|
1335
|
+
version === TERMINAL_DELIVERY_BINARY_CAPABILITY_VERSION ||
|
|
1336
|
+
version === TERMINAL_PROJECTION_CAPABILITY_VERSION ||
|
|
1337
|
+
version === TERMINAL_DELIVERY_BINARY_LOCAL_CAPABILITY_VERSION ||
|
|
1338
|
+
version === TERMINAL_PROJECTION_LOCAL_CAPABILITY_VERSION ||
|
|
1339
|
+
version === TERMINAL_GRAPHICS_COMPRESSED_CAPABILITY_VERSION ||
|
|
1340
|
+
version === TERMINAL_GRAPHICS_COMPRESSED_LOCAL_CAPABILITY_VERSION) === true;
|
|
1244
1341
|
// Renderers that report cell pixels learn up front that this daemon
|
|
1245
1342
|
// accepts them, before any image exists.
|
|
1246
1343
|
const cellPixels = this.#descriptor.terminalDelivery?.protocolVersions.includes(TERMINAL_GRAPHICS_CELL_PIXELS_CAPABILITY_VERSION) === true;
|
|
@@ -1268,6 +1365,9 @@ export class PaneStreamLiveConnection {
|
|
|
1268
1365
|
...(zlib ? state : rawGraphicsState(state)),
|
|
1269
1366
|
...(cellPixels ? { cellPixels: true } : {}),
|
|
1270
1367
|
...(preciseCellPixels ? { preciseCellPixels: true } : {}),
|
|
1368
|
+
...(channel.graphicsBinary ? { binaryBlobs: true } : {}),
|
|
1369
|
+
...(channel.graphicsCompressed ? { compressedBlobs: true } : {}),
|
|
1370
|
+
...(channel.graphicsLocal ? { localFiles: true } : {}),
|
|
1271
1371
|
},
|
|
1272
1372
|
});
|
|
1273
1373
|
if (pushed.length > 0)
|
|
@@ -1284,15 +1384,24 @@ export class PaneStreamLiveConnection {
|
|
|
1284
1384
|
placements: [],
|
|
1285
1385
|
cellPixels: true,
|
|
1286
1386
|
...(preciseCellPixels ? { preciseCellPixels: true } : {}),
|
|
1387
|
+
...(channel.graphicsBinary ? { binaryBlobs: true } : {}),
|
|
1388
|
+
...(channel.graphicsCompressed ? { compressedBlobs: true } : {}),
|
|
1389
|
+
...(channel.graphicsLocal ? { localFiles: true } : {}),
|
|
1287
1390
|
},
|
|
1288
1391
|
});
|
|
1289
1392
|
}
|
|
1290
1393
|
}
|
|
1291
|
-
#requestGraphics(pane, digests) {
|
|
1394
|
+
#requestGraphics(pane, digests, preferInline = false) {
|
|
1292
1395
|
const channel = this.#panes.get(pane);
|
|
1293
1396
|
// Requests are only meaningful after an announcement; ignore stray ones.
|
|
1294
1397
|
if (!channel || channel.closed || !channel.graphicsAnnounced)
|
|
1295
1398
|
return;
|
|
1399
|
+
if (preferInline && channel.graphicsLocal) {
|
|
1400
|
+
for (const digest of digests) {
|
|
1401
|
+
if ((channel.graphicsInline?.size ?? 0) < GRAPHICS_MAX_QUEUED_DIGESTS)
|
|
1402
|
+
channel.graphicsInline?.add(digest);
|
|
1403
|
+
}
|
|
1404
|
+
}
|
|
1296
1405
|
this.#queueGraphics(channel, digests);
|
|
1297
1406
|
}
|
|
1298
1407
|
#queueGraphics(channel, digests) {
|
|
@@ -1313,6 +1422,7 @@ export class PaneStreamLiveConnection {
|
|
|
1313
1422
|
try {
|
|
1314
1423
|
while (!this.#closed && !channel.closed && channel.graphicsQueue.length > 0) {
|
|
1315
1424
|
const digest = channel.graphicsQueue.shift();
|
|
1425
|
+
const inline = channel.graphicsInline?.delete(digest) ?? false;
|
|
1316
1426
|
const graphics = channel.delivery?.graphics;
|
|
1317
1427
|
const image = graphics?.image(digest);
|
|
1318
1428
|
if (!graphics || !image)
|
|
@@ -1339,6 +1449,49 @@ export class PaneStreamLiveConnection {
|
|
|
1339
1449
|
continue;
|
|
1340
1450
|
const format = raw ? (image.format === "rgba-zlib" ? "rgba" : "rgb") : image.format;
|
|
1341
1451
|
const total = data.byteLength;
|
|
1452
|
+
if (!inline && channel.graphicsLocal && !raw && this.#localImages) {
|
|
1453
|
+
for (const [id, lease] of this.#localLeases)
|
|
1454
|
+
if (lease.expiresAt <= Date.now())
|
|
1455
|
+
this.#localLeases.delete(id);
|
|
1456
|
+
if (this.#localLeases.size < 64) {
|
|
1457
|
+
try {
|
|
1458
|
+
const lease = await this.#localImages.acquire({
|
|
1459
|
+
generation: this.#localImages.identity.generation,
|
|
1460
|
+
client: this.#descriptor.leaseId,
|
|
1461
|
+
digest,
|
|
1462
|
+
bytes: data,
|
|
1463
|
+
});
|
|
1464
|
+
if (this.#closed || channel.closed || graphics.image(digest) !== image) {
|
|
1465
|
+
await this.#localImages.release(lease);
|
|
1466
|
+
continue;
|
|
1467
|
+
}
|
|
1468
|
+
this.#localLeases.set(lease.id, {
|
|
1469
|
+
pane: channel.semanticPaneId,
|
|
1470
|
+
expiresAt: lease.expiresAt,
|
|
1471
|
+
});
|
|
1472
|
+
this.#sendFrame(null, {
|
|
1473
|
+
type: "terminal-graphics-local",
|
|
1474
|
+
pane: channel.semanticPaneId,
|
|
1475
|
+
generation: lease.generation,
|
|
1476
|
+
leaseId: lease.id,
|
|
1477
|
+
path: lease.path,
|
|
1478
|
+
expiresAt: lease.expiresAt,
|
|
1479
|
+
blob: {
|
|
1480
|
+
digest,
|
|
1481
|
+
format,
|
|
1482
|
+
width: image.width,
|
|
1483
|
+
height: image.height,
|
|
1484
|
+
total,
|
|
1485
|
+
offset: 0,
|
|
1486
|
+
},
|
|
1487
|
+
});
|
|
1488
|
+
continue;
|
|
1489
|
+
}
|
|
1490
|
+
catch {
|
|
1491
|
+
/* Optional transport: retain the negotiated inline fallback. */
|
|
1492
|
+
}
|
|
1493
|
+
}
|
|
1494
|
+
}
|
|
1342
1495
|
for (let offset = 0; offset < total; offset += TERMINAL_GRAPHICS_BLOB_CHUNK_BYTES) {
|
|
1343
1496
|
while ((this.#socket.bufferedAmount ?? 0) > GRAPHICS_SEND_WINDOW_BYTES) {
|
|
1344
1497
|
if (this.#closed || channel.closed)
|
|
@@ -1352,6 +1505,43 @@ export class PaneStreamLiveConnection {
|
|
|
1352
1505
|
if (offset > 0 && graphics.image(digest) !== image)
|
|
1353
1506
|
break;
|
|
1354
1507
|
const end = Math.min(total, offset + TERMINAL_GRAPHICS_BLOB_CHUNK_BYTES);
|
|
1508
|
+
if (channel.graphicsBinary) {
|
|
1509
|
+
const header = {
|
|
1510
|
+
pane: channel.semanticPaneId,
|
|
1511
|
+
blob: {
|
|
1512
|
+
digest,
|
|
1513
|
+
format,
|
|
1514
|
+
width: image.width,
|
|
1515
|
+
height: image.height,
|
|
1516
|
+
total,
|
|
1517
|
+
offset,
|
|
1518
|
+
},
|
|
1519
|
+
};
|
|
1520
|
+
const compressed = channel.graphicsCompressed
|
|
1521
|
+
? await compressGraphicsChunk(header, data.subarray(offset, end))
|
|
1522
|
+
: null;
|
|
1523
|
+
// Compression yields: a pane may close or replace this image meanwhile.
|
|
1524
|
+
if (this.#closed || channel.closed)
|
|
1525
|
+
return;
|
|
1526
|
+
if (graphics.image(digest) !== image)
|
|
1527
|
+
break;
|
|
1528
|
+
if (compressed) {
|
|
1529
|
+
this.#sendEncoded(null, Buffer.from(compressed), true);
|
|
1530
|
+
continue;
|
|
1531
|
+
}
|
|
1532
|
+
this.#sendEncoded(null, Buffer.from(encodeTerminalGraphicsBinary({
|
|
1533
|
+
pane: channel.semanticPaneId,
|
|
1534
|
+
blob: {
|
|
1535
|
+
digest,
|
|
1536
|
+
format,
|
|
1537
|
+
width: image.width,
|
|
1538
|
+
height: image.height,
|
|
1539
|
+
total,
|
|
1540
|
+
offset,
|
|
1541
|
+
},
|
|
1542
|
+
}, data.subarray(offset, end))), true);
|
|
1543
|
+
continue;
|
|
1544
|
+
}
|
|
1355
1545
|
this.#sendFrame(null, {
|
|
1356
1546
|
type: "terminal-graphics-blob",
|
|
1357
1547
|
pane: channel.semanticPaneId,
|
|
@@ -1508,6 +1698,8 @@ export class PaneStreamLiveConnection {
|
|
|
1508
1698
|
if (channel.closed)
|
|
1509
1699
|
return;
|
|
1510
1700
|
channel.closed = true;
|
|
1701
|
+
this.#surfaceDemands.get(channel.semanticPaneId)?.close();
|
|
1702
|
+
this.#surfaceDemands.delete(channel.semanticPaneId);
|
|
1511
1703
|
const sub = channel.sub;
|
|
1512
1704
|
channel.sub = null;
|
|
1513
1705
|
if (sub)
|
|
@@ -1671,7 +1863,12 @@ export class PaneStreamLiveConnection {
|
|
|
1671
1863
|
if (this.#closed || this.#socket.readyState !== WS_OPEN)
|
|
1672
1864
|
return;
|
|
1673
1865
|
const encoded = JSON.stringify(frame);
|
|
1674
|
-
|
|
1866
|
+
this.#sendEncoded(pane, encoded, false);
|
|
1867
|
+
}
|
|
1868
|
+
#sendEncoded(pane, encoded, binary) {
|
|
1869
|
+
if (this.#closed || this.#socket.readyState !== WS_OPEN)
|
|
1870
|
+
return;
|
|
1871
|
+
const bytes = Buffer.byteLength(encoded);
|
|
1675
1872
|
if (pane !== null) {
|
|
1676
1873
|
this.#ledger.take(this.#clientId, pane, "ws-send-buffer", bytes);
|
|
1677
1874
|
if (this.#deliveryAcks)
|
|
@@ -1680,7 +1877,7 @@ export class PaneStreamLiveConnection {
|
|
|
1680
1877
|
this.#sendQueue.push({ pane, remaining: bytes });
|
|
1681
1878
|
this.#sentBytesTotal += bytes;
|
|
1682
1879
|
try {
|
|
1683
|
-
this.#socket.send(encoded, { binary
|
|
1880
|
+
this.#socket.send(encoded, { binary });
|
|
1684
1881
|
}
|
|
1685
1882
|
catch {
|
|
1686
1883
|
this.close(1011, "stream-unavailable");
|
|
@@ -1914,6 +2111,24 @@ export class PaneStreamLiveConnection {
|
|
|
1914
2111
|
});
|
|
1915
2112
|
return;
|
|
1916
2113
|
}
|
|
2114
|
+
if (frame.type === "terminal-projection-receipt") {
|
|
2115
|
+
const channel = this.#deliveryChannel(frame.receipt);
|
|
2116
|
+
if (!channel)
|
|
2117
|
+
return;
|
|
2118
|
+
if (!channel.delivery?.projectionReceipt)
|
|
2119
|
+
return this.#failProtocol("protocol-error");
|
|
2120
|
+
channel.delivery.projectionReceipt(frame.receipt);
|
|
2121
|
+
return;
|
|
2122
|
+
}
|
|
2123
|
+
if (frame.type === "terminal-projection-materialize") {
|
|
2124
|
+
const channel = this.#deliveryChannel(frame.request);
|
|
2125
|
+
if (!channel)
|
|
2126
|
+
return;
|
|
2127
|
+
if (!channel.delivery?.materialize)
|
|
2128
|
+
return this.#failProtocol("protocol-error");
|
|
2129
|
+
channel.delivery.materialize(frame.request);
|
|
2130
|
+
return;
|
|
2131
|
+
}
|
|
1917
2132
|
if (frame.type === "terminal-delivery-ack") {
|
|
1918
2133
|
const channel = this.#deliveryChannel(frame.ack);
|
|
1919
2134
|
if (!channel)
|
|
@@ -1945,8 +2160,138 @@ export class PaneStreamLiveConnection {
|
|
|
1945
2160
|
this.#acceptSemanticIntent(frame.operationId, frame.intent);
|
|
1946
2161
|
return;
|
|
1947
2162
|
}
|
|
2163
|
+
if (frame.type === "terminal-surface-watch") {
|
|
2164
|
+
if (byteLength > TERMINAL_SURFACE_MAX_CONTROL_BYTES ||
|
|
2165
|
+
frame.generation !== this.#sessionRuntimeBinding?.generation ||
|
|
2166
|
+
!this.#descriptor.terminalDelivery?.protocolVersions.includes(TERMINAL_SURFACE_CAPABILITY_VERSION) ||
|
|
2167
|
+
!this.#nativeSurfaces ||
|
|
2168
|
+
this.#surfaceReceiver)
|
|
2169
|
+
return this.#failProtocol("protocol-error");
|
|
2170
|
+
if (this.#surfaceViewer)
|
|
2171
|
+
return;
|
|
2172
|
+
this.#surfaceViewer = new NativeSurfaceViewer(this.#nativeSurfaces, this.#descriptor.panes, (control) => {
|
|
2173
|
+
if (this.#closed)
|
|
2174
|
+
return false;
|
|
2175
|
+
this.#surfaceControl(control.type);
|
|
2176
|
+
this.#sendFrame(null, control);
|
|
2177
|
+
return !this.#closed;
|
|
2178
|
+
}, (pane, generation) => {
|
|
2179
|
+
const channel = this.#panes.get(pane);
|
|
2180
|
+
const address = channel?.deliveryAddress;
|
|
2181
|
+
return !this.#closed &&
|
|
2182
|
+
channel &&
|
|
2183
|
+
!channel.closed &&
|
|
2184
|
+
channel.delivery &&
|
|
2185
|
+
address?.generation === generation
|
|
2186
|
+
? address.deliveryNonce
|
|
2187
|
+
: null;
|
|
2188
|
+
});
|
|
2189
|
+
this.#surfaceViewer.start();
|
|
2190
|
+
return;
|
|
2191
|
+
}
|
|
2192
|
+
if (frame.type === "terminal-surface-receiver") {
|
|
2193
|
+
if (this.#surfaceViewer) {
|
|
2194
|
+
if (byteLength > TERMINAL_SURFACE_MAX_CONTROL_BYTES || !this.#surfaceViewer.receive(frame))
|
|
2195
|
+
this.#failProtocol("protocol-error");
|
|
2196
|
+
return;
|
|
2197
|
+
}
|
|
2198
|
+
if (byteLength > TERMINAL_SURFACE_MAX_CONTROL_BYTES ||
|
|
2199
|
+
!this.#descriptor.terminalDelivery ||
|
|
2200
|
+
frame.generation !== this.#sessionRuntimeBinding?.generation) {
|
|
2201
|
+
return this.#failProtocol("protocol-error");
|
|
2202
|
+
}
|
|
2203
|
+
if (this.#surfaceReceiver) {
|
|
2204
|
+
// Parsed schema order is deterministic. A duplicate cannot change the
|
|
2205
|
+
// challenge, kernel identity or endpoint, nor amplify fallback replies.
|
|
2206
|
+
if (JSON.stringify(frame) !== JSON.stringify(this.#surfaceReceiver)) {
|
|
2207
|
+
return this.#failProtocol("protocol-error");
|
|
2208
|
+
}
|
|
2209
|
+
return;
|
|
2210
|
+
}
|
|
2211
|
+
this.#surfaceReceiver = frame;
|
|
2212
|
+
if (this.#descriptor.terminalDelivery.protocolVersions.includes(TERMINAL_SURFACE_CAPABILITY_VERSION)) {
|
|
2213
|
+
const native = this.#nativeSurfaces?.open(frame, this.#descriptor.panes, (control) => {
|
|
2214
|
+
if (this.#closed)
|
|
2215
|
+
return false;
|
|
2216
|
+
this.#surfaceControl(control.type);
|
|
2217
|
+
this.#sendFrame(null, control);
|
|
2218
|
+
return !this.#closed;
|
|
2219
|
+
}, (pane, generation) => {
|
|
2220
|
+
const channel = this.#panes.get(pane);
|
|
2221
|
+
const address = channel?.deliveryAddress;
|
|
2222
|
+
if (this.#closed ||
|
|
2223
|
+
!channel ||
|
|
2224
|
+
channel.closed ||
|
|
2225
|
+
!channel.delivery ||
|
|
2226
|
+
!address ||
|
|
2227
|
+
address.generation !== generation)
|
|
2228
|
+
return null;
|
|
2229
|
+
return address.deliveryNonce;
|
|
2230
|
+
}) ?? null;
|
|
2231
|
+
if (this.#closed) {
|
|
2232
|
+
native?.close();
|
|
2233
|
+
return;
|
|
2234
|
+
}
|
|
2235
|
+
this.#surfaceSession = native;
|
|
2236
|
+
if (native)
|
|
2237
|
+
return;
|
|
2238
|
+
}
|
|
2239
|
+
// No provider/capability means no PID/slot lookup and no inferred locality.
|
|
2240
|
+
this.#sendFrame(null, {
|
|
2241
|
+
type: "terminal-surface-fallback",
|
|
2242
|
+
version: 1,
|
|
2243
|
+
generation: frame.generation,
|
|
2244
|
+
connectionNonce: frame.connectionNonce,
|
|
2245
|
+
reason: "unsupported",
|
|
2246
|
+
});
|
|
2247
|
+
return;
|
|
2248
|
+
}
|
|
2249
|
+
if (frame.type === "terminal-surface-fallback") {
|
|
2250
|
+
if (this.#surfaceViewer) {
|
|
2251
|
+
if (byteLength > TERMINAL_SURFACE_MAX_CONTROL_BYTES || !this.#surfaceViewer.fallback(frame))
|
|
2252
|
+
this.#failProtocol("protocol-error");
|
|
2253
|
+
return;
|
|
2254
|
+
}
|
|
2255
|
+
if (byteLength > TERMINAL_SURFACE_MAX_CONTROL_BYTES ||
|
|
2256
|
+
frame.generation !== this.#surfaceReceiver?.generation ||
|
|
2257
|
+
frame.connectionNonce !== this.#surfaceReceiver.connectionNonce) {
|
|
2258
|
+
return this.#failProtocol("protocol-error");
|
|
2259
|
+
}
|
|
2260
|
+
this.#surfaceSession?.fallback(frame.reason);
|
|
2261
|
+
return;
|
|
2262
|
+
}
|
|
2263
|
+
if (frame.type === "terminal-surface-retired") {
|
|
2264
|
+
if (this.#surfaceViewer) {
|
|
2265
|
+
if (byteLength > TERMINAL_SURFACE_MAX_CONTROL_BYTES || !this.#surfaceViewer.retire(frame))
|
|
2266
|
+
this.#failProtocol("protocol-error");
|
|
2267
|
+
return;
|
|
2268
|
+
}
|
|
2269
|
+
if (byteLength <= TERMINAL_SURFACE_MAX_CONTROL_BYTES &&
|
|
2270
|
+
frame.generation === this.#surfaceReceiver?.generation &&
|
|
2271
|
+
frame.connectionNonce === this.#surfaceReceiver.connectionNonce &&
|
|
2272
|
+
this.#surfaceSession?.retire(frame.sequence))
|
|
2273
|
+
return;
|
|
2274
|
+
// Unissued/replayed ACKs must not retire another socket's native storage.
|
|
2275
|
+
return this.#failProtocol("protocol-error");
|
|
2276
|
+
}
|
|
1948
2277
|
if (frame.type === "terminal-graphics-request") {
|
|
1949
|
-
this.#requestGraphics(frame.pane, frame.digests);
|
|
2278
|
+
this.#requestGraphics(frame.pane, frame.digests, frame.preferInline === true);
|
|
2279
|
+
return;
|
|
2280
|
+
}
|
|
2281
|
+
if (frame.type === "terminal-graphics-local-release") {
|
|
2282
|
+
const lease = this.#localLeases.get(frame.leaseId);
|
|
2283
|
+
if (lease &&
|
|
2284
|
+
lease.pane === frame.pane &&
|
|
2285
|
+
frame.generation === this.#localImages?.identity.generation) {
|
|
2286
|
+
this.#localLeases.delete(frame.leaseId);
|
|
2287
|
+
void this.#localImages
|
|
2288
|
+
?.release({
|
|
2289
|
+
generation: frame.generation,
|
|
2290
|
+
client: this.#descriptor.leaseId,
|
|
2291
|
+
id: frame.leaseId,
|
|
2292
|
+
})
|
|
2293
|
+
.catch(() => { });
|
|
2294
|
+
}
|
|
1950
2295
|
return;
|
|
1951
2296
|
}
|
|
1952
2297
|
if (frame.type === "terminal-cell-pixels") {
|
|
@@ -2127,6 +2472,12 @@ export class PaneStreamLiveConnection {
|
|
|
2127
2472
|
this.#evaluateResume(pane);
|
|
2128
2473
|
}
|
|
2129
2474
|
#acceptInput(pane, seq, kind, data, frameBytes, performanceTraceId, causalProbe, ingressAtMicros = null, callbackAtSharedMicros = null, ingressAtSharedMicros = null, expectedLifetime) {
|
|
2475
|
+
if (kind === "bytes" &&
|
|
2476
|
+
(!this.#sessionRuntimeBinding ||
|
|
2477
|
+
!this.#descriptor.terminalDelivery?.protocolVersions.includes(PANE_STREAM_INPUT_BYTES_CAPABILITY_VERSION))) {
|
|
2478
|
+
this.#failProtocol("input-rejected");
|
|
2479
|
+
return;
|
|
2480
|
+
}
|
|
2130
2481
|
if (expectedLifetime &&
|
|
2131
2482
|
(!this.#sessionRuntimeBinding ||
|
|
2132
2483
|
!this.#descriptor.terminalDelivery?.protocolVersions.includes(PANE_STREAM_INPUT_LIFETIME_CAPABILITY_VERSION))) {
|
|
@@ -2227,8 +2578,10 @@ export class PaneStreamLiveConnection {
|
|
|
2227
2578
|
: undefined, expectedLifetime);
|
|
2228
2579
|
else if (kind === "text")
|
|
2229
2580
|
channel.sub.sendText(data);
|
|
2230
|
-
else
|
|
2581
|
+
else if (kind === "key")
|
|
2231
2582
|
channel.sub.sendKey(data);
|
|
2583
|
+
else
|
|
2584
|
+
throw new Error("Byte input requires semantic runtime");
|
|
2232
2585
|
let ackStartedAtMicros = null;
|
|
2233
2586
|
let ackStartedAtSharedMicros = null;
|
|
2234
2587
|
if (trace) {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { NativeSurfaceProviderRegistry } from "../graphics/native-surface-provider.js";
|
|
1
2
|
import { SessionRuntimeTransportBinder } from "../session-runtime/transport-binding.js";
|
|
2
3
|
import { PaneStreamLeaseManager } from "./lease-manager.js";
|
|
3
4
|
import { PaneStreamAdmissionCoordinator, } from "./pane-stream-websocket.js";
|
|
@@ -8,14 +9,22 @@ import { PaneStreamAdmissionCoordinator, } from "./pane-stream-websocket.js";
|
|
|
8
9
|
*/
|
|
9
10
|
export class PaneStreamRuntime {
|
|
10
11
|
coordinator;
|
|
12
|
+
nativeSurfaces;
|
|
11
13
|
#disposePromise = null;
|
|
12
14
|
constructor(options) {
|
|
15
|
+
this.nativeSurfaces =
|
|
16
|
+
options.nativeSurfaces ??
|
|
17
|
+
(process.platform === "darwin"
|
|
18
|
+
? new NativeSurfaceProviderRegistry(options.daemonInstanceId)
|
|
19
|
+
: undefined);
|
|
13
20
|
const leaseManager = new PaneStreamLeaseManager({
|
|
14
21
|
daemonInstanceId: options.daemonInstanceId,
|
|
15
22
|
});
|
|
16
23
|
const transportBinder = new SessionRuntimeTransportBinder(options.sessionRuntimeRegistry);
|
|
17
24
|
this.coordinator = new PaneStreamAdmissionCoordinator({
|
|
18
25
|
...options.admission,
|
|
26
|
+
localImages: options.localImages,
|
|
27
|
+
nativeSurfaces: this.nativeSurfaces,
|
|
19
28
|
daemonInstanceId: options.daemonInstanceId,
|
|
20
29
|
webSocketUrl: options.webSocketUrl,
|
|
21
30
|
leaseManager,
|
|
@@ -42,6 +51,7 @@ export class PaneStreamRuntime {
|
|
|
42
51
|
dispose() {
|
|
43
52
|
if (!this.#disposePromise) {
|
|
44
53
|
this.#disposePromise = (async () => {
|
|
54
|
+
this.nativeSurfaces?.close();
|
|
45
55
|
await this.coordinator.shutdown();
|
|
46
56
|
})();
|
|
47
57
|
}
|
|
@@ -1653,6 +1653,8 @@ class SessionRuntimeConsumerImpl {
|
|
|
1653
1653
|
negotiation: upstream.negotiation,
|
|
1654
1654
|
closed: upstream.closed,
|
|
1655
1655
|
ack: (ack) => upstream.ack(ack),
|
|
1656
|
+
...(upstream.projectionReceipt ? { projectionReceipt: upstream.projectionReceipt } : {}),
|
|
1657
|
+
...(upstream.materialize ? { materialize: upstream.materialize } : {}),
|
|
1656
1658
|
nack: (nack) => upstream.nack(nack),
|
|
1657
1659
|
setVisibility: (visibility) => upstream.setVisibility(visibility),
|
|
1658
1660
|
close: async () => {
|