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
package/package.json
CHANGED
|
@@ -50,6 +50,8 @@ export * from "./session-runtime.ts";
|
|
|
50
50
|
export * from "./terminal-replica.ts";
|
|
51
51
|
export * from "./terminal-delivery.ts";
|
|
52
52
|
export * from "./terminal-graphics.ts";
|
|
53
|
+
export * from "./terminal-graphics-compressed.ts";
|
|
54
|
+
export * from "./terminal-surfaces.ts";
|
|
53
55
|
export * from "./terminal-runtime-inventory.ts";
|
|
54
56
|
export * from "./experience-shell.ts";
|
|
55
57
|
export * from "./application-shell.ts";
|
|
@@ -120,3 +122,7 @@ export * from "./tmux-agent-open.ts";
|
|
|
120
122
|
export * from "./tmux-server-diagnostics.ts";
|
|
121
123
|
|
|
122
124
|
export * from "./terminal-history-anchor.ts";
|
|
125
|
+
|
|
126
|
+
export * from "./terminal-delivery-binary-chunk.ts";
|
|
127
|
+
|
|
128
|
+
export * from "./terminal-projection.ts";
|
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
import {
|
|
2
|
+
TerminalSurfaceWatchSchemaZ,
|
|
3
|
+
TerminalSurfaceReceiverSchemaZ,
|
|
4
|
+
TerminalSurfaceAvailableSchemaZ,
|
|
5
|
+
TerminalSurfacePeerSchemaZ,
|
|
6
|
+
TerminalSurfaceOfferSchemaZ,
|
|
7
|
+
TerminalSurfaceRetiredSchemaZ,
|
|
8
|
+
TerminalSurfaceFallbackSchemaZ,
|
|
9
|
+
} from "./terminal-surfaces.ts";
|
|
10
|
+
import {
|
|
11
|
+
TerminalProjectionEnvelopeSchemaZ,
|
|
12
|
+
TerminalProjectionReceiptSchemaZ,
|
|
13
|
+
TerminalProjectionMaterializeSchemaZ,
|
|
14
|
+
} from "./terminal-projection.ts";
|
|
1
15
|
import { z } from "zod";
|
|
2
16
|
import { isTmuxServerPaneStreamPath } from "./tmux-server-scope.ts";
|
|
3
17
|
import {
|
|
@@ -45,6 +59,7 @@ import {
|
|
|
45
59
|
SessionRuntimePresenceStateSchemaZ,
|
|
46
60
|
SessionRuntimeSemanticIntentSchemaZ,
|
|
47
61
|
SessionRuntimeTerminalKeyInputSchemaZ,
|
|
62
|
+
SessionRuntimeTerminalBytesInputSchemaZ,
|
|
48
63
|
SessionRuntimeTerminalKeyNameSchemaZ,
|
|
49
64
|
SessionRuntimeTerminalTextInputSchemaZ,
|
|
50
65
|
} from "./session-runtime.ts";
|
|
@@ -232,6 +247,8 @@ export const PaneStreamKeyNameSchemaZ = SessionRuntimeTerminalKeyNameSchemaZ;
|
|
|
232
247
|
|
|
233
248
|
/** Negotiated only with callers offering this additive delivery capability. */
|
|
234
249
|
export const PANE_STREAM_INPUT_LIFETIME_CAPABILITY_VERSION = 105;
|
|
250
|
+
/** Exact hex bytes require explicit offer + ready acknowledgement; older daemons may omit it. */
|
|
251
|
+
export const PANE_STREAM_INPUT_BYTES_CAPABILITY_VERSION = 106;
|
|
235
252
|
export const PaneStreamInputLifetimeSchemaZ = z
|
|
236
253
|
.object({
|
|
237
254
|
generation: z.string().min(1).max(256),
|
|
@@ -254,6 +271,7 @@ export const PaneStreamInputFrameSchemaZ = z
|
|
|
254
271
|
.discriminatedUnion("kind", [
|
|
255
272
|
SessionRuntimeTerminalTextInputSchemaZ.extend(PaneStreamInputFrameMetadataShape),
|
|
256
273
|
SessionRuntimeTerminalKeyInputSchemaZ.extend(PaneStreamInputFrameMetadataShape),
|
|
274
|
+
SessionRuntimeTerminalBytesInputSchemaZ.extend(PaneStreamInputFrameMetadataShape),
|
|
257
275
|
])
|
|
258
276
|
.superRefine((value, context) => {
|
|
259
277
|
if (!value.causalProbe) return;
|
|
@@ -279,6 +297,18 @@ export type PaneStreamConsumedFrame = z.infer<typeof PaneStreamConsumedFrameSche
|
|
|
279
297
|
export const PaneStreamTerminalDeliveryAckFrameSchemaZ = z
|
|
280
298
|
.object({ type: z.literal("terminal-delivery-ack"), ack: TerminalDeliveryAckSchemaZ })
|
|
281
299
|
.strict();
|
|
300
|
+
export const PaneStreamTerminalProjectionReceiptFrameSchemaZ = z
|
|
301
|
+
.object({
|
|
302
|
+
type: z.literal("terminal-projection-receipt"),
|
|
303
|
+
receipt: TerminalProjectionReceiptSchemaZ,
|
|
304
|
+
})
|
|
305
|
+
.strict();
|
|
306
|
+
export const PaneStreamTerminalProjectionMaterializeFrameSchemaZ = z
|
|
307
|
+
.object({
|
|
308
|
+
type: z.literal("terminal-projection-materialize"),
|
|
309
|
+
request: TerminalProjectionMaterializeSchemaZ,
|
|
310
|
+
})
|
|
311
|
+
.strict();
|
|
282
312
|
export const PaneStreamTerminalDeliveryNackFrameSchemaZ = z
|
|
283
313
|
.object({ type: z.literal("terminal-delivery-nack"), nack: TerminalDeliveryNackSchemaZ })
|
|
284
314
|
.strict();
|
|
@@ -363,6 +393,7 @@ export const PaneStreamClockProbeFrameSchemaZ = z
|
|
|
363
393
|
export const PaneStreamTerminalGraphicsRequestFrameSchemaZ = z
|
|
364
394
|
.object({
|
|
365
395
|
type: z.literal("terminal-graphics-request"),
|
|
396
|
+
preferInline: z.literal(true).optional(),
|
|
366
397
|
pane: PaneStreamSemanticPaneIdSchemaZ,
|
|
367
398
|
digests: z
|
|
368
399
|
.array(TerminalGraphicsDigestSchemaZ)
|
|
@@ -371,6 +402,15 @@ export const PaneStreamTerminalGraphicsRequestFrameSchemaZ = z
|
|
|
371
402
|
})
|
|
372
403
|
.strict();
|
|
373
404
|
|
|
405
|
+
export const PaneStreamTerminalGraphicsLocalReleaseFrameSchemaZ = z
|
|
406
|
+
.object({
|
|
407
|
+
type: z.literal("terminal-graphics-local-release"),
|
|
408
|
+
pane: PaneStreamSemanticPaneIdSchemaZ,
|
|
409
|
+
generation: z.uuid(),
|
|
410
|
+
leaseId: z.uuid(),
|
|
411
|
+
})
|
|
412
|
+
.strict();
|
|
413
|
+
|
|
374
414
|
/** The renderer's terminal cell size in device pixels (see capability 103). */
|
|
375
415
|
export const PaneStreamTerminalCellPixelsFrameSchemaZ = z
|
|
376
416
|
.object({
|
|
@@ -391,6 +431,8 @@ export const PaneStreamClientFrameSchemaZ = z.union([
|
|
|
391
431
|
PaneStreamInputFrameSchemaZ,
|
|
392
432
|
PaneStreamConsumedFrameSchemaZ,
|
|
393
433
|
PaneStreamTerminalDeliveryAckFrameSchemaZ,
|
|
434
|
+
PaneStreamTerminalProjectionReceiptFrameSchemaZ,
|
|
435
|
+
PaneStreamTerminalProjectionMaterializeFrameSchemaZ,
|
|
394
436
|
PaneStreamTerminalDeliveryNackFrameSchemaZ,
|
|
395
437
|
PaneStreamTerminalDeliveryVisibilityFrameSchemaZ,
|
|
396
438
|
PaneStreamSemanticIntentFrameSchemaZ,
|
|
@@ -401,7 +443,12 @@ export const PaneStreamClientFrameSchemaZ = z.union([
|
|
|
401
443
|
PaneStreamAuthorityReleaseFrameSchemaZ,
|
|
402
444
|
PaneStreamClockProbeFrameSchemaZ,
|
|
403
445
|
PaneStreamTerminalGraphicsRequestFrameSchemaZ,
|
|
446
|
+
PaneStreamTerminalGraphicsLocalReleaseFrameSchemaZ,
|
|
404
447
|
PaneStreamTerminalCellPixelsFrameSchemaZ,
|
|
448
|
+
TerminalSurfaceWatchSchemaZ,
|
|
449
|
+
TerminalSurfaceReceiverSchemaZ,
|
|
450
|
+
TerminalSurfaceRetiredSchemaZ,
|
|
451
|
+
TerminalSurfaceFallbackSchemaZ,
|
|
405
452
|
]);
|
|
406
453
|
export type PaneStreamClientFrame = z.infer<typeof PaneStreamClientFrameSchemaZ>;
|
|
407
454
|
|
|
@@ -421,6 +468,7 @@ export const PaneStreamReadyFrameSchemaZ = z
|
|
|
421
468
|
.object({
|
|
422
469
|
type: z.literal("ready"),
|
|
423
470
|
inputLifetime: z.literal(true).optional(),
|
|
471
|
+
inputBytes: z.literal(true).optional(),
|
|
424
472
|
protocolVersion: z.literal(PANE_STREAM_PROTOCOL_VERSION),
|
|
425
473
|
daemonInstanceId: BoundedIdentitySchemaZ,
|
|
426
474
|
requestId: z.uuid(),
|
|
@@ -678,6 +726,13 @@ export const PaneStreamTerminalDeliveryEnvelopeFrameSchemaZ = z
|
|
|
678
726
|
envelope: TerminalDeliveryEnvelopeSchemaZ,
|
|
679
727
|
})
|
|
680
728
|
.strict();
|
|
729
|
+
export const PaneStreamTerminalProjectionEnvelopeFrameSchemaZ = z
|
|
730
|
+
.object({
|
|
731
|
+
type: z.literal("terminal-projection-envelope"),
|
|
732
|
+
pane: PaneStreamSemanticPaneIdSchemaZ,
|
|
733
|
+
envelope: TerminalProjectionEnvelopeSchemaZ,
|
|
734
|
+
})
|
|
735
|
+
.strict();
|
|
681
736
|
export const PaneStreamTerminalDeliveryChunkFrameSchemaZ = z
|
|
682
737
|
.object({
|
|
683
738
|
type: z.literal("terminal-delivery-chunk"),
|
|
@@ -709,6 +764,22 @@ export const PaneStreamTerminalGraphicsBlobFrameSchemaZ = z
|
|
|
709
764
|
data: Base64SchemaZ(Math.ceil(TERMINAL_GRAPHICS_BLOB_CHUNK_BYTES / 3) * 4).min(4),
|
|
710
765
|
})
|
|
711
766
|
.strict();
|
|
767
|
+
export const PaneStreamTerminalGraphicsLocalFrameSchemaZ = z
|
|
768
|
+
.object({
|
|
769
|
+
type: z.literal("terminal-graphics-local"),
|
|
770
|
+
pane: PaneStreamSemanticPaneIdSchemaZ,
|
|
771
|
+
generation: z.uuid(),
|
|
772
|
+
leaseId: z.uuid(),
|
|
773
|
+
path: z
|
|
774
|
+
.string()
|
|
775
|
+
.min(1)
|
|
776
|
+
.max(4096)
|
|
777
|
+
.refine((path) => path.startsWith("/") && !path.includes("\0")),
|
|
778
|
+
expiresAt: z.number().int().positive().safe(),
|
|
779
|
+
blob: TerminalGraphicsBlobSchemaZ.extend({ offset: z.literal(0) }),
|
|
780
|
+
})
|
|
781
|
+
.strict();
|
|
782
|
+
|
|
712
783
|
export const PaneStreamSemanticIntentAckFrameSchemaZ = z
|
|
713
784
|
.object({
|
|
714
785
|
type: z.literal("semantic-intent-ack"),
|
|
@@ -797,6 +868,10 @@ export const PaneStreamErrorFrameSchemaZ = z
|
|
|
797
868
|
.strict();
|
|
798
869
|
|
|
799
870
|
export const PaneStreamServerFrameSchemaZ = z.discriminatedUnion("type", [
|
|
871
|
+
TerminalSurfaceAvailableSchemaZ,
|
|
872
|
+
TerminalSurfacePeerSchemaZ,
|
|
873
|
+
TerminalSurfaceOfferSchemaZ,
|
|
874
|
+
TerminalSurfaceFallbackSchemaZ,
|
|
800
875
|
PaneStreamReadyFrameSchemaZ,
|
|
801
876
|
PaneStreamSeedBatchFrameSchemaZ,
|
|
802
877
|
PaneStreamOutputFrameSchemaZ,
|
|
@@ -811,10 +886,12 @@ export const PaneStreamServerFrameSchemaZ = z.discriminatedUnion("type", [
|
|
|
811
886
|
PaneStreamCausalCellFailureFrameSchemaZ,
|
|
812
887
|
PaneStreamTerminalDeliveryReadyFrameSchemaZ,
|
|
813
888
|
PaneStreamTerminalDeliveryEnvelopeFrameSchemaZ,
|
|
889
|
+
PaneStreamTerminalProjectionEnvelopeFrameSchemaZ,
|
|
814
890
|
PaneStreamTerminalDeliveryChunkFrameSchemaZ,
|
|
815
891
|
PaneStreamTerminalDeliveryFaultFrameSchemaZ,
|
|
816
892
|
PaneStreamTerminalGraphicsFrameSchemaZ,
|
|
817
893
|
PaneStreamTerminalGraphicsBlobFrameSchemaZ,
|
|
894
|
+
PaneStreamTerminalGraphicsLocalFrameSchemaZ,
|
|
818
895
|
PaneStreamSemanticIntentAckFrameSchemaZ,
|
|
819
896
|
PaneStreamViewportAckFrameSchemaZ,
|
|
820
897
|
PaneStreamAuthoritySnapshotFrameSchemaZ,
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { TerminalAttachmentSemanticPaneIdSchemaZ } from "./semantic-identity.ts";
|
|
3
|
+
import { TERMINAL_DELIVERY_CHUNK_BYTES } from "./terminal-delivery.ts";
|
|
4
|
+
export const TerminalDeliveryBinaryChunkHeaderSchemaZ = z
|
|
5
|
+
.object({
|
|
6
|
+
pane: TerminalAttachmentSemanticPaneIdSchemaZ,
|
|
7
|
+
transactionId: z.uuid(),
|
|
8
|
+
index: z.number().int().min(0).max(255),
|
|
9
|
+
})
|
|
10
|
+
.strict();
|
|
11
|
+
export type TerminalDeliveryBinaryChunkHeader = z.infer<
|
|
12
|
+
typeof TerminalDeliveryBinaryChunkHeaderSchemaZ
|
|
13
|
+
>;
|
|
14
|
+
/** TDC1 + u32be metadata length + strict header + unchanged representation chunk. */
|
|
15
|
+
export function encodeTerminalDeliveryBinaryChunk(
|
|
16
|
+
header: TerminalDeliveryBinaryChunkHeader,
|
|
17
|
+
bytes: Uint8Array,
|
|
18
|
+
): Uint8Array {
|
|
19
|
+
const parsed = TerminalDeliveryBinaryChunkHeaderSchemaZ.parse(header);
|
|
20
|
+
const json = new TextEncoder().encode(JSON.stringify(parsed));
|
|
21
|
+
if (json.length > 4096 || bytes.length > TERMINAL_DELIVERY_CHUNK_BYTES)
|
|
22
|
+
throw new TypeError("Binary delivery chunk bound");
|
|
23
|
+
const result = new Uint8Array(8 + json.length + bytes.length);
|
|
24
|
+
result.set([84, 68, 67, 49]);
|
|
25
|
+
new DataView(result.buffer).setUint32(4, json.length, false);
|
|
26
|
+
result.set(json, 8);
|
|
27
|
+
result.set(bytes, 8 + json.length);
|
|
28
|
+
return result;
|
|
29
|
+
}
|
|
30
|
+
export function decodeTerminalDeliveryBinaryChunk(data: Uint8Array): {
|
|
31
|
+
header: TerminalDeliveryBinaryChunkHeader;
|
|
32
|
+
bytes: Uint8Array;
|
|
33
|
+
} {
|
|
34
|
+
if (
|
|
35
|
+
data.length < 9 ||
|
|
36
|
+
data.length > 8 + 4096 + TERMINAL_DELIVERY_CHUNK_BYTES ||
|
|
37
|
+
data[0] !== 84 ||
|
|
38
|
+
data[1] !== 68 ||
|
|
39
|
+
data[2] !== 67 ||
|
|
40
|
+
data[3] !== 49
|
|
41
|
+
)
|
|
42
|
+
throw new TypeError("Invalid binary delivery packet");
|
|
43
|
+
const length = new DataView(data.buffer, data.byteOffset, data.byteLength).getUint32(4, false);
|
|
44
|
+
if (
|
|
45
|
+
length < 1 ||
|
|
46
|
+
length > 4096 ||
|
|
47
|
+
8 + length > data.length ||
|
|
48
|
+
data.length - 8 - length > TERMINAL_DELIVERY_CHUNK_BYTES
|
|
49
|
+
)
|
|
50
|
+
throw new TypeError("Invalid binary delivery header bound");
|
|
51
|
+
const header = TerminalDeliveryBinaryChunkHeaderSchemaZ.parse(
|
|
52
|
+
JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(data.subarray(8, 8 + length))),
|
|
53
|
+
);
|
|
54
|
+
return { header, bytes: data.subarray(8 + length) };
|
|
55
|
+
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { TerminalProjectionEnvelope } from "./terminal-projection.ts";
|
|
1
2
|
import { z } from "zod";
|
|
2
3
|
import { CausalCellProofV1SchemaZ } from "./causal-cell.ts";
|
|
3
4
|
import { TerminalAttachmentSemanticPaneIdSchemaZ } from "./semantic-identity.ts";
|
|
@@ -13,6 +14,11 @@ import {
|
|
|
13
14
|
export const STOCK_CAPTURE_TAB_UNAVAILABLE =
|
|
14
15
|
"This tmux server cannot provide an exact snapshot of saved tab cells. Continue this session in native tmux, or use a new session started with tmux-ide's bundled server.";
|
|
15
16
|
|
|
17
|
+
/** Opt-in bundles:109 adds binary cells+107 graphics;110 also adds108 local image leases.
|
|
18
|
+
* Offer compact in encodings for old-daemon compatibility; new daemons respond binary explicitly. */
|
|
19
|
+
export const TERMINAL_DELIVERY_BINARY_CAPABILITY_VERSION = 109;
|
|
20
|
+
export const TERMINAL_DELIVERY_BINARY_LOCAL_CAPABILITY_VERSION = 110;
|
|
21
|
+
|
|
16
22
|
export const TERMINAL_DELIVERY_PROTOCOL_VERSION = 1 as const;
|
|
17
23
|
export const TERMINAL_DELIVERY_CHUNK_BYTES = 256 * 1024;
|
|
18
24
|
export const TERMINAL_DELIVERY_PATCH_TO_SEED_BYTES = 512 * 1024;
|
|
@@ -20,6 +26,7 @@ export const TERMINAL_DELIVERY_MAX_REPRESENTATION_BYTES = 16 * 1024 * 1024;
|
|
|
20
26
|
|
|
21
27
|
export const TerminalDeliveryEncodingSchemaZ = z.enum([
|
|
22
28
|
"semantic-compact-v1",
|
|
29
|
+
"semantic-binary-v1",
|
|
23
30
|
"semantic-v1",
|
|
24
31
|
"ansi-diff-v1",
|
|
25
32
|
"ansi-raw-v1",
|
|
@@ -28,7 +35,8 @@ export type TerminalDeliveryEncoding = z.infer<typeof TerminalDeliveryEncodingSc
|
|
|
28
35
|
|
|
29
36
|
export const TerminalDeliveryOfferSchemaZ = z
|
|
30
37
|
.object({
|
|
31
|
-
|
|
38
|
+
// Interactive binary/graphics offers use eight slots; native surfaces add one.
|
|
39
|
+
protocolVersions: z.array(z.number().int().positive()).min(1).max(9),
|
|
32
40
|
encodings: z.array(TerminalDeliveryEncodingSchemaZ).min(1).max(4),
|
|
33
41
|
richPlacements: z.boolean(),
|
|
34
42
|
})
|
|
@@ -46,18 +54,22 @@ export const TerminalDeliveryNegotiatedSchemaZ = z
|
|
|
46
54
|
protocolVersion: z.literal(TERMINAL_DELIVERY_PROTOCOL_VERSION),
|
|
47
55
|
encoding: TerminalDeliveryEncodingSchemaZ,
|
|
48
56
|
fallbackEncoding: z.literal("semantic-v1").nullable().optional(),
|
|
57
|
+
alternateScreenProjection: z.literal("deferred-history-v1").optional(),
|
|
49
58
|
richPlacements: z.boolean(),
|
|
50
59
|
generation: SessionRuntimeGenerationSchemaZ,
|
|
51
60
|
deliveryNonce: z.uuid(),
|
|
52
61
|
})
|
|
53
62
|
.strict()
|
|
54
63
|
.superRefine((value, context) => {
|
|
64
|
+
if (value.alternateScreenProjection && value.encoding !== "semantic-binary-v1")
|
|
65
|
+
context.addIssue({ code: "custom", message: "projection requires binary semantic delivery" });
|
|
55
66
|
if (value.fallbackEncoding && value.encoding !== "semantic-compact-v1")
|
|
56
67
|
context.addIssue({ code: "custom", message: "fallback encoding requires compact semantic" });
|
|
57
68
|
if (
|
|
58
69
|
value.richPlacements &&
|
|
59
70
|
value.encoding !== "semantic-v1" &&
|
|
60
|
-
value.encoding !== "semantic-compact-v1"
|
|
71
|
+
value.encoding !== "semantic-compact-v1" &&
|
|
72
|
+
value.encoding !== "semantic-binary-v1"
|
|
61
73
|
)
|
|
62
74
|
context.addIssue({ code: "custom", message: "rich placements require semantic delivery" });
|
|
63
75
|
});
|
|
@@ -118,7 +130,10 @@ export const TerminalDeliveryEnvelopeSchemaZ = DeliveryAddressSchemaZ.extend({
|
|
|
118
130
|
})
|
|
119
131
|
.strict()
|
|
120
132
|
.superRefine((value, context) => {
|
|
121
|
-
const semantic =
|
|
133
|
+
const semantic =
|
|
134
|
+
value.encoding === "semantic-v1" ||
|
|
135
|
+
value.encoding === "semantic-compact-v1" ||
|
|
136
|
+
value.encoding === "semantic-binary-v1";
|
|
122
137
|
const expectedChunks = Math.max(
|
|
123
138
|
1,
|
|
124
139
|
Math.ceil(value.representationBytes / TERMINAL_DELIVERY_CHUNK_BYTES),
|
|
@@ -206,6 +221,7 @@ export type TerminalDeliveryNack = z.infer<typeof TerminalDeliveryNackSchemaZ>;
|
|
|
206
221
|
|
|
207
222
|
export type TerminalDeliveryServerMessage =
|
|
208
223
|
| TerminalDeliveryEnvelope
|
|
224
|
+
| TerminalProjectionEnvelope
|
|
209
225
|
| TerminalDeliveryChunk
|
|
210
226
|
| TerminalDeliveryFault;
|
|
211
227
|
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import {
|
|
3
|
+
TerminalGraphicsBinaryHeaderSchemaZ,
|
|
4
|
+
TERMINAL_GRAPHICS_BINARY_HEADER_BYTES,
|
|
5
|
+
TERMINAL_GRAPHICS_BLOB_CHUNK_BYTES,
|
|
6
|
+
} from "./terminal-graphics.ts";
|
|
7
|
+
|
|
8
|
+
/** TGB2 uses an independent zlib stream per chunk. Digest/offset/total still
|
|
9
|
+
* describe the original image bytes. Decoders must require exact output length,
|
|
10
|
+
* stream termination and complete input consumption before hashing or painting. */
|
|
11
|
+
export const TerminalGraphicsCompressedHeaderSchemaZ = TerminalGraphicsBinaryHeaderSchemaZ.extend({
|
|
12
|
+
compression: z.literal("zlib"),
|
|
13
|
+
decodedBytes: z.number().int().min(1).max(TERMINAL_GRAPHICS_BLOB_CHUNK_BYTES),
|
|
14
|
+
}).superRefine((header, context) => {
|
|
15
|
+
if (
|
|
16
|
+
header.blob.offset + header.decodedBytes > header.blob.total ||
|
|
17
|
+
(header.blob.format !== "rgb" && header.blob.format !== "rgba")
|
|
18
|
+
)
|
|
19
|
+
context.addIssue({ code: "custom", message: "Invalid compressed graphics range or format" });
|
|
20
|
+
});
|
|
21
|
+
export type TerminalGraphicsCompressedHeader = z.infer<
|
|
22
|
+
typeof TerminalGraphicsCompressedHeaderSchemaZ
|
|
23
|
+
>;
|
|
24
|
+
export function encodeTerminalGraphicsCompressed(
|
|
25
|
+
header: TerminalGraphicsCompressedHeader,
|
|
26
|
+
bytes: Uint8Array,
|
|
27
|
+
): Uint8Array {
|
|
28
|
+
const parsed = TerminalGraphicsCompressedHeaderSchemaZ.parse(header);
|
|
29
|
+
const json = new TextEncoder().encode(JSON.stringify(parsed));
|
|
30
|
+
if (
|
|
31
|
+
json.length > TERMINAL_GRAPHICS_BINARY_HEADER_BYTES ||
|
|
32
|
+
bytes.length < 1 ||
|
|
33
|
+
bytes.length >= parsed.decodedBytes
|
|
34
|
+
)
|
|
35
|
+
throw new Error("Invalid compressed graphics bounds");
|
|
36
|
+
const result = new Uint8Array(8 + json.length + bytes.length);
|
|
37
|
+
result.set([84, 71, 66, 50]);
|
|
38
|
+
new DataView(result.buffer).setUint32(4, json.length, false);
|
|
39
|
+
result.set(json, 8);
|
|
40
|
+
result.set(bytes, 8 + json.length);
|
|
41
|
+
return result;
|
|
42
|
+
}
|
|
43
|
+
/** Only parses the envelope; inflation belongs on the receiving worker. */
|
|
44
|
+
export function decodeTerminalGraphicsCompressed(data: Uint8Array): {
|
|
45
|
+
header: TerminalGraphicsCompressedHeader;
|
|
46
|
+
bytes: Uint8Array;
|
|
47
|
+
} {
|
|
48
|
+
if (
|
|
49
|
+
data.length < 10 ||
|
|
50
|
+
data.length > 8 + TERMINAL_GRAPHICS_BINARY_HEADER_BYTES + TERMINAL_GRAPHICS_BLOB_CHUNK_BYTES ||
|
|
51
|
+
data[0] !== 84 ||
|
|
52
|
+
data[1] !== 71 ||
|
|
53
|
+
data[2] !== 66 ||
|
|
54
|
+
data[3] !== 50
|
|
55
|
+
)
|
|
56
|
+
throw new Error("Invalid compressed graphics frame");
|
|
57
|
+
const length = new DataView(data.buffer, data.byteOffset, data.byteLength).getUint32(4, false);
|
|
58
|
+
if (length < 1 || length > TERMINAL_GRAPHICS_BINARY_HEADER_BYTES || 8 + length >= data.length)
|
|
59
|
+
throw new Error("Invalid compressed graphics header");
|
|
60
|
+
const header = TerminalGraphicsCompressedHeaderSchemaZ.parse(
|
|
61
|
+
JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(data.subarray(8, 8 + length))),
|
|
62
|
+
);
|
|
63
|
+
const bytes = data.subarray(8 + length);
|
|
64
|
+
if (bytes.length >= header.decodedBytes) throw new Error("Invalid compressed graphics payload");
|
|
65
|
+
return { header, bytes };
|
|
66
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
+
import { TerminalAttachmentSemanticPaneIdSchemaZ } from "./semantic-identity.ts";
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* Kitty graphics protocol side channel.
|
|
@@ -15,6 +16,16 @@ import { z } from "zod";
|
|
|
15
16
|
* version; daemons that know it send graphics frames only to such renderers.
|
|
16
17
|
*/
|
|
17
18
|
export const TERMINAL_GRAPHICS_CAPABILITY_VERSION = 101;
|
|
19
|
+
/** Raw binary blob frames; requires the graphics side channel (101). */
|
|
20
|
+
export const TERMINAL_GRAPHICS_BINARY_CAPABILITY_VERSION = 107;
|
|
21
|
+
/** Bundles 113/114 include projection 111/112 and bounded lossless raw-pixel chunks.
|
|
22
|
+
* Older daemons ignore these and retain the offered compact/text and JSON graphics fallback. */
|
|
23
|
+
export const TERMINAL_GRAPHICS_COMPRESSED_CAPABILITY_VERSION = 113;
|
|
24
|
+
export const TERMINAL_GRAPHICS_COMPRESSED_LOCAL_CAPABILITY_VERSION = 114;
|
|
25
|
+
/** Verified same-host file leases, including binary-blob fallback (107).
|
|
26
|
+
* Offer 108 instead of 107 to retain the existing eight-capability bound.
|
|
27
|
+
* Never infer locality from a loopback URL. */
|
|
28
|
+
export const TERMINAL_GRAPHICS_LOCAL_CAPABILITY_VERSION = 108;
|
|
18
29
|
/** Renderers that inflate `rgba-zlib`/`rgb-zlib` themselves offer this too. */
|
|
19
30
|
export const TERMINAL_GRAPHICS_ZLIB_CAPABILITY_VERSION = 102;
|
|
20
31
|
/**
|
|
@@ -92,6 +103,9 @@ export const TerminalGraphicsStateSchemaZ = z
|
|
|
92
103
|
/** The daemon accepts `terminal-cell-pixels` (only sent to renderers offering 103). */
|
|
93
104
|
cellPixels: z.literal(true).optional(),
|
|
94
105
|
preciseCellPixels: z.literal(true).optional(),
|
|
106
|
+
binaryBlobs: z.literal(true).optional(),
|
|
107
|
+
compressedBlobs: z.literal(true).optional(),
|
|
108
|
+
localFiles: z.literal(true).optional(),
|
|
95
109
|
})
|
|
96
110
|
.strict();
|
|
97
111
|
export type TerminalGraphicsState = z.infer<typeof TerminalGraphicsStateSchemaZ>;
|
|
@@ -116,3 +130,62 @@ export type TerminalGraphicsServerMessage =
|
|
|
116
130
|
readonly blob: TerminalGraphicsBlob;
|
|
117
131
|
readonly bytes: Uint8Array;
|
|
118
132
|
};
|
|
133
|
+
|
|
134
|
+
/** TGB1 + u32be header bytes + strict JSON {pane,blob} + raw payload.
|
|
135
|
+
* No compression is applied here: PNG and negotiated zlib are already encoded.
|
|
136
|
+
*/
|
|
137
|
+
export const TERMINAL_GRAPHICS_BINARY_HEADER_BYTES = 4096;
|
|
138
|
+
export const TerminalGraphicsBinaryHeaderSchemaZ = z
|
|
139
|
+
.object({
|
|
140
|
+
pane: TerminalAttachmentSemanticPaneIdSchemaZ,
|
|
141
|
+
blob: TerminalGraphicsBlobSchemaZ,
|
|
142
|
+
})
|
|
143
|
+
.strict();
|
|
144
|
+
export type TerminalGraphicsBinaryHeader = z.infer<typeof TerminalGraphicsBinaryHeaderSchemaZ>;
|
|
145
|
+
export function encodeTerminalGraphicsBinary(
|
|
146
|
+
header: TerminalGraphicsBinaryHeader,
|
|
147
|
+
bytes: Uint8Array,
|
|
148
|
+
): Uint8Array {
|
|
149
|
+
const parsed = TerminalGraphicsBinaryHeaderSchemaZ.parse(header);
|
|
150
|
+
const json = new TextEncoder().encode(JSON.stringify(parsed));
|
|
151
|
+
if (
|
|
152
|
+
json.length > TERMINAL_GRAPHICS_BINARY_HEADER_BYTES ||
|
|
153
|
+
bytes.length < 1 ||
|
|
154
|
+
bytes.length > TERMINAL_GRAPHICS_BLOB_CHUNK_BYTES ||
|
|
155
|
+
parsed.blob.offset + bytes.length > parsed.blob.total
|
|
156
|
+
)
|
|
157
|
+
throw new Error("Invalid binary graphics bounds");
|
|
158
|
+
const result = new Uint8Array(8 + json.length + bytes.length);
|
|
159
|
+
result.set([84, 71, 66, 49]);
|
|
160
|
+
new DataView(result.buffer).setUint32(4, json.length, false);
|
|
161
|
+
result.set(json, 8);
|
|
162
|
+
result.set(bytes, 8 + json.length);
|
|
163
|
+
return result;
|
|
164
|
+
}
|
|
165
|
+
export function decodeTerminalGraphicsBinary(data: Uint8Array): {
|
|
166
|
+
header: TerminalGraphicsBinaryHeader;
|
|
167
|
+
bytes: Uint8Array;
|
|
168
|
+
} {
|
|
169
|
+
if (
|
|
170
|
+
data.length < 10 ||
|
|
171
|
+
data.length > 8 + TERMINAL_GRAPHICS_BINARY_HEADER_BYTES + TERMINAL_GRAPHICS_BLOB_CHUNK_BYTES ||
|
|
172
|
+
data[0] !== 84 ||
|
|
173
|
+
data[1] !== 71 ||
|
|
174
|
+
data[2] !== 66 ||
|
|
175
|
+
data[3] !== 49
|
|
176
|
+
)
|
|
177
|
+
throw new Error("Invalid binary graphics frame");
|
|
178
|
+
const length = new DataView(data.buffer, data.byteOffset, data.byteLength).getUint32(4, false);
|
|
179
|
+
if (length < 1 || length > TERMINAL_GRAPHICS_BINARY_HEADER_BYTES || 8 + length >= data.length)
|
|
180
|
+
throw new Error("Invalid binary graphics header");
|
|
181
|
+
const header = TerminalGraphicsBinaryHeaderSchemaZ.parse(
|
|
182
|
+
JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(data.subarray(8, 8 + length))),
|
|
183
|
+
);
|
|
184
|
+
const bytes = data.subarray(8 + length);
|
|
185
|
+
if (
|
|
186
|
+
bytes.length > TERMINAL_GRAPHICS_BLOB_CHUNK_BYTES ||
|
|
187
|
+
header.blob.offset + bytes.length > header.blob.total
|
|
188
|
+
)
|
|
189
|
+
throw new Error("Invalid binary graphics payload");
|
|
190
|
+
return { header, bytes };
|
|
191
|
+
}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import {
|
|
3
|
+
TerminalReplicaSnapshotSchemaZ,
|
|
4
|
+
TerminalReplicaPatchPayloadSchemaZ,
|
|
5
|
+
TerminalReplicaTombstonePayloadSchemaZ,
|
|
6
|
+
} from "./terminal-replica.ts";
|
|
7
|
+
import { TerminalAttachmentSemanticPaneIdSchemaZ } from "./semantic-identity.ts";
|
|
8
|
+
import { SessionRuntimeGenerationSchemaZ } from "./session-runtime.ts";
|
|
9
|
+
import { WorkspaceIdSchemaZ } from "./workspace-state.ts";
|
|
10
|
+
import {
|
|
11
|
+
TERMINAL_DELIVERY_CHUNK_BYTES,
|
|
12
|
+
TERMINAL_DELIVERY_MAX_REPRESENTATION_BYTES,
|
|
13
|
+
} from "./terminal-delivery.ts";
|
|
14
|
+
|
|
15
|
+
/** Bundles111/112 include109/110 respectively; the old-compatible encoding offer stays compact. */
|
|
16
|
+
export const TERMINAL_PROJECTION_CAPABILITY_VERSION = 111;
|
|
17
|
+
export const TERMINAL_PROJECTION_LOCAL_CAPABILITY_VERSION = 112;
|
|
18
|
+
const Hash = z.string().regex(/^[0-9a-f]{16}$/u);
|
|
19
|
+
const Revision = z.number().int().nonnegative().max(Number.MAX_SAFE_INTEGER);
|
|
20
|
+
export const TerminalDeferredHistorySchemaZ = z
|
|
21
|
+
.object({ rows: z.number().int().min(0).max(10000), digest: Hash })
|
|
22
|
+
.strict();
|
|
23
|
+
export type TerminalDeferredHistory = z.infer<typeof TerminalDeferredHistorySchemaZ>;
|
|
24
|
+
const ProjectionModes = TerminalReplicaSnapshotSchemaZ.shape.modes.extend({
|
|
25
|
+
alternateScreen: z.literal(true),
|
|
26
|
+
});
|
|
27
|
+
/** A viewport projection is not a materialized canonical snapshot. History is deliberately absent. */
|
|
28
|
+
export const TerminalProjectionSnapshotSchemaZ = TerminalReplicaSnapshotSchemaZ.omit({
|
|
29
|
+
history: true,
|
|
30
|
+
})
|
|
31
|
+
.extend({
|
|
32
|
+
cols: z.number().int().min(1).max(4096),
|
|
33
|
+
rows: z.number().int().min(1).max(4096),
|
|
34
|
+
grid: TerminalReplicaSnapshotSchemaZ.shape.grid.max(4096),
|
|
35
|
+
modes: ProjectionModes,
|
|
36
|
+
placements: TerminalReplicaSnapshotSchemaZ.shape.placements.max(4096),
|
|
37
|
+
deferredHistory: TerminalDeferredHistorySchemaZ,
|
|
38
|
+
})
|
|
39
|
+
.strict()
|
|
40
|
+
.superRefine((value, ctx) => {
|
|
41
|
+
if (
|
|
42
|
+
value.grid.length !== value.rows ||
|
|
43
|
+
value.grid.some((row) => row.cells.length !== value.cols) ||
|
|
44
|
+
value.cols * value.rows > 1_000_000
|
|
45
|
+
)
|
|
46
|
+
ctx.addIssue({ code: "custom", message: "Invalid projection grid dimensions" });
|
|
47
|
+
if (
|
|
48
|
+
value.cursor.x >= value.cols ||
|
|
49
|
+
value.cursor.y >= value.rows ||
|
|
50
|
+
value.placements.some((p) => p.row + p.rows > value.rows || p.column + p.columns > value.cols)
|
|
51
|
+
)
|
|
52
|
+
ctx.addIssue({ code: "custom", message: "Projection metadata outside viewport" });
|
|
53
|
+
});
|
|
54
|
+
export type TerminalProjectionSnapshot = z.infer<typeof TerminalProjectionSnapshotSchemaZ>;
|
|
55
|
+
export const TerminalProjectionPatchSchemaZ = TerminalReplicaPatchPayloadSchemaZ.omit({
|
|
56
|
+
history: true,
|
|
57
|
+
historyDelta: true,
|
|
58
|
+
})
|
|
59
|
+
.extend({
|
|
60
|
+
modes: ProjectionModes.optional(),
|
|
61
|
+
dimensions: z
|
|
62
|
+
.object({ cols: z.number().int().min(1).max(4096), rows: z.number().int().min(1).max(4096) })
|
|
63
|
+
.strict()
|
|
64
|
+
.optional(),
|
|
65
|
+
placements: TerminalReplicaSnapshotSchemaZ.shape.placements.max(4096).optional(),
|
|
66
|
+
deferredHistory: TerminalDeferredHistorySchemaZ,
|
|
67
|
+
rows: TerminalReplicaPatchPayloadSchemaZ.shape.rows.max(4096),
|
|
68
|
+
})
|
|
69
|
+
.strict();
|
|
70
|
+
export type TerminalProjectionPatch = z.infer<typeof TerminalProjectionPatchSchemaZ>;
|
|
71
|
+
export const TerminalProjectionPayloadSchemaZ = z
|
|
72
|
+
.discriminatedUnion("frame", [
|
|
73
|
+
z
|
|
74
|
+
.object({
|
|
75
|
+
frame: z.literal("seed"),
|
|
76
|
+
revision: Revision,
|
|
77
|
+
projection: TerminalProjectionSnapshotSchemaZ,
|
|
78
|
+
})
|
|
79
|
+
.strict(),
|
|
80
|
+
z
|
|
81
|
+
.object({
|
|
82
|
+
frame: z.literal("patch"),
|
|
83
|
+
baseRevision: Revision,
|
|
84
|
+
revision: Revision,
|
|
85
|
+
patch: TerminalProjectionPatchSchemaZ,
|
|
86
|
+
})
|
|
87
|
+
.strict(),
|
|
88
|
+
z
|
|
89
|
+
.object({
|
|
90
|
+
frame: z.literal("tombstone"),
|
|
91
|
+
baseRevision: Revision,
|
|
92
|
+
revision: Revision,
|
|
93
|
+
tombstone: TerminalReplicaTombstonePayloadSchemaZ,
|
|
94
|
+
})
|
|
95
|
+
.strict(),
|
|
96
|
+
])
|
|
97
|
+
.superRefine((value, ctx) => {
|
|
98
|
+
if (value.frame !== "seed" && value.revision <= value.baseRevision)
|
|
99
|
+
ctx.addIssue({ code: "custom", message: "Projection revision must advance" });
|
|
100
|
+
});
|
|
101
|
+
export type TerminalProjectionPayload = z.infer<typeof TerminalProjectionPayloadSchemaZ>;
|
|
102
|
+
const Address = z.object({
|
|
103
|
+
workspaceName: WorkspaceIdSchemaZ,
|
|
104
|
+
semanticPaneId: TerminalAttachmentSemanticPaneIdSchemaZ,
|
|
105
|
+
generation: SessionRuntimeGenerationSchemaZ,
|
|
106
|
+
incarnation: z.string().min(1).max(256),
|
|
107
|
+
deliveryNonce: z.uuid(),
|
|
108
|
+
});
|
|
109
|
+
const Proof = Address.extend({
|
|
110
|
+
transactionId: z.uuid(),
|
|
111
|
+
/** Source canonical root/revision; receipt does not assert history materialization. */
|
|
112
|
+
canonicalRevision: Revision,
|
|
113
|
+
canonicalStateHash: Hash,
|
|
114
|
+
projectionStateHash: Hash,
|
|
115
|
+
representationHash: Hash,
|
|
116
|
+
});
|
|
117
|
+
export const TerminalProjectionEnvelopeSchemaZ = Proof.extend({
|
|
118
|
+
type: z.literal("terminal.projection"),
|
|
119
|
+
performanceTraceId: z.uuid().optional(),
|
|
120
|
+
protocolVersion: z.literal(1),
|
|
121
|
+
encoding: z.literal("alternate-projection-binary-v1"),
|
|
122
|
+
frame: z.enum(["seed", "patch", "tombstone"]),
|
|
123
|
+
baseRevision: Revision.nullable(),
|
|
124
|
+
representationBytes: z.number().int().min(1).max(TERMINAL_DELIVERY_MAX_REPRESENTATION_BYTES),
|
|
125
|
+
chunkCount: z.number().int().min(1).max(256),
|
|
126
|
+
canonicalEquivalent: z.literal(false),
|
|
127
|
+
history: z.literal("deferred"),
|
|
128
|
+
richPlacements: z.boolean(),
|
|
129
|
+
})
|
|
130
|
+
.strict()
|
|
131
|
+
.superRefine((value, ctx) => {
|
|
132
|
+
if (value.chunkCount !== Math.ceil(value.representationBytes / TERMINAL_DELIVERY_CHUNK_BYTES))
|
|
133
|
+
ctx.addIssue({ code: "custom", message: "Projection chunk count mismatch" });
|
|
134
|
+
if (
|
|
135
|
+
value.frame === "seed"
|
|
136
|
+
? value.baseRevision !== null
|
|
137
|
+
: value.baseRevision === null || value.canonicalRevision <= value.baseRevision
|
|
138
|
+
)
|
|
139
|
+
ctx.addIssue({ code: "custom", message: "Projection base revision mismatch" });
|
|
140
|
+
});
|
|
141
|
+
export type TerminalProjectionEnvelope = z.infer<typeof TerminalProjectionEnvelopeSchemaZ>;
|
|
142
|
+
/** This is never a TerminalDeliveryAck and must not advance a complete baseline. */
|
|
143
|
+
export const TerminalProjectionReceiptSchemaZ = Proof.extend({
|
|
144
|
+
type: z.literal("terminal.projection.receipt"),
|
|
145
|
+
}).strict();
|
|
146
|
+
export type TerminalProjectionReceipt = z.infer<typeof TerminalProjectionReceiptSchemaZ>;
|
|
147
|
+
export const TerminalProjectionMaterializeSchemaZ = Address.extend({
|
|
148
|
+
type: z.literal("terminal.projection.materialize"),
|
|
149
|
+
requestId: z.uuid(),
|
|
150
|
+
canonicalRevision: Revision,
|
|
151
|
+
projectionStateHash: Hash,
|
|
152
|
+
}).strict();
|
|
153
|
+
export type TerminalProjectionMaterialize = z.infer<typeof TerminalProjectionMaterializeSchemaZ>;
|