tmux-ide 2.9.2 → 2.9.4
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/LICENSE +1 -1
- package/README.md +121 -140
- package/bin/cli.js +2457 -727
- package/package.json +23 -8
- package/packages/contracts/src/desktop-host.ts +3 -0
- package/packages/contracts/src/saved-machines.ts +19 -0
- package/packages/contracts/src/terminal-replica.ts +1 -1
- package/packages/core/package.json +3 -2
- package/packages/core/src/terminal-delivery.ts +51 -3
- package/packages/core/src/terminal-fnv64-wasm.ts +4 -3
- package/packages/core/src/terminal-replica-hash-cache.ts +129 -31
- package/packages/core/src/terminal-replica-owned-row.ts +27 -0
- package/packages/core/src/terminal-replica.ts +13 -28
- package/packages/daemon/dist/command-center/daemon-fleet-facts-observer.js +96 -10
- package/packages/daemon/dist/command-center/resources/saved-machine-route.js +40 -1
- package/packages/daemon/dist/command-center/ws-events.js +5 -24
- package/packages/daemon/dist/lib/canonical-daemon-bootstrap.js +8 -0
- package/packages/daemon/dist/lib/canonical-daemon.js +28 -2
- package/packages/daemon/dist/lib/daemon-embed.js +1 -1
- package/packages/daemon/dist/lib/daemon-service-manager.js +122 -0
- package/packages/daemon/dist/lib/daemon-service-plan.js +127 -0
- package/packages/daemon/dist/lib/daemon-service.js +259 -0
- package/packages/daemon/dist/lib/install-origin.js +2 -0
- package/packages/daemon/dist/lib/local-fleet-request.js +9 -3
- package/packages/daemon/dist/lib/log.js +6 -10
- package/packages/daemon/dist/lib/managed-installer-update.js +67 -0
- package/packages/daemon/dist/lib/{tui-download-lock.js → private-operation-lock.js} +11 -11
- package/packages/daemon/dist/lib/remote-daemon-info.js +3 -2
- package/packages/daemon/dist/lib/remote-daemon-lifecycle.js +4 -4
- package/packages/daemon/dist/lib/remote-tmux-command.js +10 -0
- package/packages/daemon/dist/lib/runtime-namespace.js +28 -16
- package/packages/daemon/dist/lib/saved-machines.js +40 -2
- package/packages/daemon/dist/lib/ssh-daemon-transport.js +24 -9
- package/packages/daemon/dist/lib/tmux-server-owner.js +1 -1
- package/packages/daemon/dist/lib/tmux-server-registration.js +21 -3
- package/packages/daemon/dist/lib/tui-binary.js +2 -2
- package/packages/daemon/dist/lib/update.js +18 -0
- package/packages/daemon/dist/lib/workspace-multiplexer-verbs.js +24 -1
- package/packages/daemon/dist/machines.js +40 -4
- 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/terminal/attachments/direct-websocket.js +4 -1
- package/packages/daemon/dist/terminal/attachments/native-runtime.js +22 -13
- package/packages/daemon/dist/terminal/mirror/mirror-service.js +101 -3
- package/packages/daemon/dist/terminal/mirror/registered-window-guard.js +62 -0
- package/packages/daemon/dist/terminal/mirror/session-channel.js +75 -4
- package/packages/daemon/dist/terminal/mirror/shared-window-index.js +45 -0
- package/packages/daemon/dist/terminal/pane-stream/pane-stream-websocket.js +11 -1
- package/packages/daemon/dist/terminal/session-runtime/multiplexer-backend.js +1 -0
- package/packages/daemon/dist/terminal/session-runtime/registry.js +56 -7
- package/packages/daemon/dist/terminal/session-runtime/semantic-mutation-executor.js +3 -1
- package/packages/daemon/dist/tui/integrations/claude-agent-teams.js +264 -0
- package/packages/daemon/dist/tui/mirror/dialog-model.js +2 -35
- package/packages/daemon/dist/tui/mirror/runtime/application-daemon-authority-owner.js +8 -0
- package/packages/daemon/dist/tui/mirror/runtime/application-home-fleet.js +20 -2
- package/packages/daemon/dist/tui/mirror/runtime/application-machine-agents.js +7 -1
- package/packages/daemon/dist/tui/mirror/runtime/application-machine-authority.js +59 -9
- package/packages/daemon/dist/tui/mirror/runtime/application-machine-navigation.js +27 -19
- package/packages/daemon/dist/tui/mirror/runtime/application-machine-sidebar.jsx +23 -18
- package/packages/daemon/dist/tui/mirror/runtime/application-machine-startup.js +31 -2
- package/packages/daemon/dist/tui/mirror/runtime/application-palette-search-owner.js +7 -3
- package/packages/daemon/dist/tui/mirror/runtime/application-performance-log.js +3 -0
- package/packages/daemon/dist/tui/mirror/runtime/application-terminal-input-ingress.js +146 -2
- package/packages/daemon/dist/tui/mirror/runtime/application-terminal-interaction-controller.js +201 -50
- package/packages/daemon/dist/tui/mirror/runtime/bounded-performance-record-writer.js +50 -10
- package/packages/daemon/dist/tui/mirror/runtime/terminal-fast-lane-renderer-adapter.js +6 -5
- package/packages/daemon/dist/tui/mirror/runtime/terminal-pane-input-router.js +3 -0
- package/packages/daemon/dist/tui/mirror/runtime/workspace-terminal-fast-lane.js +8 -2
- package/packages/daemon/dist/tui/mirror/terminal-text.js +35 -0
- package/packages/daemon/dist/tui/mirror/workspace/connection-feedback.js +5 -3
- package/packages/daemon/src/command-center/daemon-fleet-facts-observer.ts +100 -10
- package/packages/daemon/src/command-center/resources/saved-machine-route.ts +48 -1
- package/packages/daemon/src/command-center/ws-events.ts +5 -25
- package/packages/daemon/src/lib/canonical-daemon-bootstrap.ts +12 -0
- package/packages/daemon/src/lib/canonical-daemon.ts +44 -2
- package/packages/daemon/src/lib/daemon-embed.ts +1 -0
- package/packages/daemon/src/lib/daemon-service-manager.ts +152 -0
- package/packages/daemon/src/lib/daemon-service-plan.ts +153 -0
- package/packages/daemon/src/lib/daemon-service.ts +301 -0
- package/packages/daemon/src/lib/install-origin.ts +5 -0
- package/packages/daemon/src/lib/local-fleet-request.ts +19 -3
- package/packages/daemon/src/lib/log.ts +13 -9
- package/packages/daemon/src/lib/managed-installer-update.ts +79 -0
- package/packages/daemon/src/lib/{tui-download-lock.ts → private-operation-lock.ts} +15 -11
- package/packages/daemon/src/lib/remote-daemon-info.ts +3 -3
- package/packages/daemon/src/lib/remote-daemon-lifecycle.ts +4 -4
- package/packages/daemon/src/lib/remote-tmux-command.ts +12 -0
- package/packages/daemon/src/lib/runtime-namespace.ts +27 -18
- package/packages/daemon/src/lib/saved-machines.ts +40 -1
- package/packages/daemon/src/lib/ssh-daemon-transport.ts +25 -7
- package/packages/daemon/src/lib/tmux-server-owner.ts +1 -0
- package/packages/daemon/src/lib/tmux-server-registration.ts +21 -3
- package/packages/daemon/src/lib/tui-binary.ts +2 -2
- package/packages/daemon/src/lib/update.ts +24 -0
- package/packages/daemon/src/lib/workspace-multiplexer-verbs.ts +22 -0
- package/packages/daemon/src/machines.ts +53 -5
- package/packages/daemon/src/terminal/attachments/direct-websocket.ts +8 -2
- package/packages/daemon/src/terminal/attachments/native-runtime.ts +28 -13
- package/packages/daemon/src/terminal/mirror/mirror-service.ts +105 -3
- package/packages/daemon/src/terminal/mirror/registered-window-guard.ts +66 -0
- package/packages/daemon/src/terminal/mirror/session-channel.ts +92 -4
- package/packages/daemon/src/terminal/mirror/shared-window-index.ts +42 -0
- package/packages/daemon/src/terminal/pane-stream/pane-stream-websocket.ts +12 -1
- package/packages/daemon/src/terminal/session-runtime/multiplexer-backend.ts +2 -0
- package/packages/daemon/src/terminal/session-runtime/registry.ts +70 -8
- package/packages/daemon/src/terminal/session-runtime/semantic-mutation-executor.ts +3 -1
- package/packages/daemon/src/tui/integrations/claude-agent-teams.ts +334 -0
- package/packages/daemon/src/tui/mirror/dialog-model.ts +2 -32
- package/packages/daemon/src/tui/mirror/runtime/application-daemon-authority-owner.ts +8 -0
- package/packages/daemon/src/tui/mirror/runtime/application-home-fleet.ts +19 -2
- package/packages/daemon/src/tui/mirror/runtime/application-machine-agents.ts +6 -1
- package/packages/daemon/src/tui/mirror/runtime/application-machine-authority.ts +60 -11
- package/packages/daemon/src/tui/mirror/runtime/application-machine-navigation.ts +39 -33
- package/packages/daemon/src/tui/mirror/runtime/application-machine-sidebar.tsx +31 -23
- package/packages/daemon/src/tui/mirror/runtime/application-machine-startup.ts +38 -2
- package/packages/daemon/src/tui/mirror/runtime/application-palette-search-owner.ts +7 -4
- package/packages/daemon/src/tui/mirror/runtime/application-performance-log.ts +3 -0
- package/packages/daemon/src/tui/mirror/runtime/application-root-v2.tsx +1 -1
- package/packages/daemon/src/tui/mirror/runtime/application-shell-view.tsx +47 -46
- package/packages/daemon/src/tui/mirror/runtime/application-terminal-input-ingress.ts +165 -2
- package/packages/daemon/src/tui/mirror/runtime/application-terminal-interaction-controller.ts +207 -53
- package/packages/daemon/src/tui/mirror/runtime/bounded-performance-record-writer.ts +49 -9
- package/packages/daemon/src/tui/mirror/runtime/terminal-fast-lane-renderer-adapter.ts +6 -5
- package/packages/daemon/src/tui/mirror/runtime/terminal-pane-input-router.ts +4 -0
- package/packages/daemon/src/tui/mirror/runtime/workspace-terminal-fast-lane.ts +8 -3
- package/packages/daemon/src/tui/mirror/terminal-text.ts +32 -0
- package/packages/daemon/src/tui/mirror/workspace/connection-feedback.ts +6 -3
- package/packages/daemon-client/src/fleet-connection-status.ts +10 -1
- package/packages/daemon-client/src/workspace-client.ts +4 -1
- package/skill/SKILL.md +30 -30
- package/packages/contracts/src/__tests__/actions-contract.test.ts +0 -119
- package/packages/contracts/src/__tests__/agent-graph-overlay.test.ts +0 -428
- package/packages/contracts/src/__tests__/app-window-mutation.test.ts +0 -51
- package/packages/contracts/src/__tests__/app-window-state.test.ts +0 -34
- package/packages/contracts/src/__tests__/application-shell.test.ts +0 -645
- package/packages/contracts/src/__tests__/automation-operations.test.ts +0 -78
- package/packages/contracts/src/__tests__/causal-cell.test.ts +0 -47
- package/packages/contracts/src/__tests__/client-view-state.test.ts +0 -115
- package/packages/contracts/src/__tests__/cohesion-fixture.test.ts +0 -106
- package/packages/contracts/src/__tests__/commands.test.ts +0 -86
- package/packages/contracts/src/__tests__/control.test.ts +0 -154
- package/packages/contracts/src/__tests__/daemon-events.test.ts +0 -405
- package/packages/contracts/src/__tests__/daemon-resources.test.ts +0 -143
- package/packages/contracts/src/__tests__/daemon-wire.test.ts +0 -149
- package/packages/contracts/src/__tests__/desktop-host.test.ts +0 -269
- package/packages/contracts/src/__tests__/desktop-missions.test.ts +0 -215
- package/packages/contracts/src/__tests__/experience-conformance.test.ts +0 -153
- package/packages/contracts/src/__tests__/experience-kernel-boundary.test.ts +0 -113
- package/packages/contracts/src/__tests__/experience-shell.test.ts +0 -65
- package/packages/contracts/src/__tests__/fixtures/daemon-wire-v2.json +0 -35
- package/packages/contracts/src/__tests__/fixtures/daemon-wire-v3.json +0 -35
- package/packages/contracts/src/__tests__/fixtures/daemon-wire-v4.json +0 -35
- package/packages/contracts/src/__tests__/fixtures/scoped-receipt.ts +0 -62
- package/packages/contracts/src/__tests__/fleet-agent-graph.test.ts +0 -231
- package/packages/contracts/src/__tests__/fleet-catalog.test.ts +0 -270
- package/packages/contracts/src/__tests__/fleet-lifecycle.test.ts +0 -62
- package/packages/contracts/src/__tests__/focus-overlay.test.ts +0 -110
- package/packages/contracts/src/__tests__/ide-config.test.ts +0 -64
- package/packages/contracts/src/__tests__/interaction-evidence.test.ts +0 -288
- package/packages/contracts/src/__tests__/interaction-receipt-v2.test.ts +0 -72
- package/packages/contracts/src/__tests__/issue-error.test.ts +0 -78
- package/packages/contracts/src/__tests__/mission-projections.test.ts +0 -186
- package/packages/contracts/src/__tests__/missions.test.ts +0 -272
- package/packages/contracts/src/__tests__/multiplexer-verbs.test.ts +0 -242
- package/packages/contracts/src/__tests__/pane-appearance.test.ts +0 -146
- package/packages/contracts/src/__tests__/pane-read-result.test.ts +0 -55
- package/packages/contracts/src/__tests__/pane-stream.test.ts +0 -536
- package/packages/contracts/src/__tests__/pane-widget-marker.test.ts +0 -327
- package/packages/contracts/src/__tests__/performance-metrics.test.ts +0 -73
- package/packages/contracts/src/__tests__/performance-qualification.test.ts +0 -137
- package/packages/contracts/src/__tests__/rich-card-widget.test.ts +0 -29
- package/packages/contracts/src/__tests__/session-runtime.test.ts +0 -512
- package/packages/contracts/src/__tests__/startup-readiness.test.ts +0 -409
- package/packages/contracts/src/__tests__/terminal-attachment-stream.test.ts +0 -72
- package/packages/contracts/src/__tests__/terminal-attachments.test.ts +0 -329
- package/packages/contracts/src/__tests__/terminal-delivery.test.ts +0 -88
- package/packages/contracts/src/__tests__/terminal-runtime-inventory.test.ts +0 -68
- package/packages/contracts/src/__tests__/terminals.test.ts +0 -87
- package/packages/contracts/src/__tests__/tmux-server-scope.test.ts +0 -166
- package/packages/contracts/src/__tests__/transport-contract-loading.test.ts +0 -91
- package/packages/contracts/src/__tests__/visual-tokens.test.ts +0 -224
- package/packages/contracts/src/__tests__/window-links.test.ts +0 -243
- package/packages/contracts/src/__tests__/workspace-changes-resource.test.ts +0 -317
- package/packages/contracts/src/__tests__/workspace-changes-view.test.ts +0 -122
- package/packages/contracts/src/__tests__/workspace-config.test.ts +0 -294
- package/packages/contracts/src/__tests__/workspace-files-resource.test.ts +0 -261
- package/packages/contracts/src/__tests__/workspace-files-tree.test.ts +0 -147
- package/packages/contracts/src/__tests__/workspace-pane-creation.test.ts +0 -249
- package/packages/contracts/src/__tests__/workspace-promotion.test.ts +0 -94
- package/packages/contracts/src/__tests__/workspace-resource-identity.test.ts +0 -90
- package/packages/contracts/src/daemon-resource-request.test.ts +0 -192
- package/packages/contracts/src/native-operation-identity.test.ts +0 -23
- package/packages/contracts/src/workspace-admission.test.ts +0 -21
- package/packages/contracts/src/workspace-catalog-resource.test.ts +0 -146
- package/packages/core/src/agent-provisioning.test.ts +0 -42
- package/packages/core/src/application-shell-session.test.ts +0 -105
- package/packages/core/src/interaction-evidence.test.ts +0 -134
- package/packages/core/src/interaction-flow.test.ts +0 -66
- package/packages/core/src/interaction-receipts.test.ts +0 -671
- package/packages/core/src/navigator.test.ts +0 -34
- package/packages/core/src/optimistic-projection-conformance.test.ts +0 -75
- package/packages/core/src/optimistic-projection.test.ts +0 -118
- package/packages/core/src/performance-metrics.test.ts +0 -121
- package/packages/core/src/performance-qualification.test.ts +0 -283
- package/packages/core/src/saved-machines.test.ts +0 -80
- package/packages/core/src/terminal-compact-cold.test.ts +0 -87
- package/packages/core/src/terminal-conformance.test.ts +0 -48
- package/packages/core/src/terminal-delivery-cache-lifetime.test.ts +0 -167
- package/packages/core/src/terminal-delivery-encode-cooperative.test.ts +0 -140
- package/packages/core/src/terminal-delivery-representation-hash.test.ts +0 -77
- package/packages/core/src/terminal-delivery.test.ts +0 -1471
- package/packages/core/src/terminal-fnv64-wasm.test.ts +0 -61
- package/packages/core/src/terminal-replica-cold.test.ts +0 -31
- package/packages/core/src/terminal-replica-cooperative.test.ts +0 -170
- package/packages/core/src/terminal-replica-hash-cache.test.ts +0 -283
- package/packages/core/src/terminal-replica.test.ts +0 -347
- package/packages/core/src/workspace-selection.test.ts +0 -63
- package/packages/daemon/dist/__tests__/support.js +0 -33
- package/packages/daemon/dist/lib/__tests__/fixtures/workspace-state-writer.js +0 -58
- package/packages/daemon/dist/lib/__tests__/installed-recovery-fixture.js +0 -400
- package/packages/daemon/dist/terminal/__tests__/MockPtyAdapter.js +0 -182
- package/packages/daemon/dist/terminal/mirror/__tests__/scripted-channel.js +0 -98
- package/packages/daemon/dist/terminal/mirror/__tests__/simulated-channel.js +0 -156
- package/packages/daemon/src/tui/mirror/__snapshots__/activity-surface-renderer.test.tsx.snap +0 -42
- package/packages/daemon/src/tui/mirror/__snapshots__/changes-terminal-surface-renderer.test.tsx.snap +0 -267
- package/packages/daemon/src/tui/mirror/__snapshots__/home-files-surface-renderer.test.tsx.snap +0 -267
- package/packages/daemon/src/tui/mirror/__snapshots__/missions-surface-renderer.test.tsx.snap +0 -134
- package/packages/daemon/src/tui/mirror/__snapshots__/recipes-gallery-renderer.test.tsx.snap +0 -141
- package/packages/daemon/src/tui/mirror/__snapshots__/shell-chrome-renderer.test.tsx.snap +0 -134
- package/packages/daemon/src/tui/mirror/runtime/__snapshots__/application-shell-view-renderer.test.tsx.snap +0 -87
- package/packages/daemon/src/tui/mirror/workspace/__snapshots__/agent-terminal-canvas-renderer.test.tsx.snap +0 -348
- package/packages/daemon/src/tui/mirror/workspace/__snapshots__/application-shell-renderer.test.tsx.snap +0 -134
- package/packages/daemon/src/tui/mirror/workspace/__snapshots__/command-palette-surface-renderer.test.tsx.snap +0 -255
- package/packages/daemon/src/tui/mirror/workspace/__snapshots__/pane-frame-renderer.test.tsx.snap +0 -525
- package/packages/daemon/src/tui/mirror/workspace/__snapshots__/terminal-pane-header-polish-renderer.test.tsx.snap +0 -31
- package/packages/daemon/src/tui/mirror/workspace/__snapshots__/workbench-shell-renderer.test.tsx.snap +0 -134
- package/packages/daemon-client/src/application-shell-session.test.ts +0 -196
- package/packages/daemon-client/src/automation-client.test.ts +0 -214
- package/packages/daemon-client/src/bootstrap-coordinator.test.ts +0 -145
- package/packages/daemon-client/src/connection-supervisor.test.ts +0 -109
- package/packages/daemon-client/src/direct-application-shell-transport.test.ts +0 -941
- package/packages/daemon-client/src/first-latest-coordinator.test.ts +0 -175
- package/packages/daemon-client/src/fleet-dial-scheduler.test.ts +0 -114
- package/packages/daemon-client/src/fleet-environments.test.ts +0 -40
- package/packages/daemon-client/src/generation-bound-store-timers.test.ts +0 -74
- package/packages/daemon-client/src/owner-action-client.test.ts +0 -245
- package/packages/daemon-client/src/pane-stream-client.test.ts +0 -2841
- package/packages/daemon-client/src/pane-stream-clock-calibration.test.ts +0 -207
- package/packages/daemon-client/src/pane-stream-loopback-benchmark.test.ts +0 -51
- package/packages/daemon-client/src/push-resource-session.test.ts +0 -509
- package/packages/daemon-client/src/resource-replica.test.ts +0 -186
- package/packages/daemon-client/src/runtime-resource-ledger.test.ts +0 -18
- package/packages/daemon-client/src/scoped-tmux-server-transport.test.ts +0 -114
- package/packages/daemon-client/src/terminal-fast-lane.test.ts +0 -835
- package/packages/daemon-client/src/tmux-server-client.test.ts +0 -279
- package/packages/daemon-client/src/tmux-server-interaction-events.test.ts +0 -230
- package/packages/daemon-client/src/workspace-catalog-v2.test.ts +0 -109
- package/packages/daemon-client/src/workspace-client-boundaries.test.ts +0 -59
- package/packages/daemon-client/src/workspace-client-operations.test.ts +0 -96
- package/packages/daemon-client/src/workspace-client.test.ts +0 -2912
- package/packages/daemon-client/src/workspace-event-supervisor.test.ts +0 -1086
- package/packages/daemon-client/src/workspace-pane-client.test.ts +0 -80
- package/packages/presentation/src/presentation-contract.test.ts +0 -63
- package/packages/tmux-bridge/src/runner.test.ts +0 -614
- package/packages/tmux-bridge/src/targeting.test.ts +0 -107
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
import { spawnSync } from "node:child_process";
|
|
2
|
-
import { fileURLToPath } from "node:url";
|
|
3
|
-
import { describe, expect, it } from "vitest";
|
|
4
|
-
|
|
5
|
-
describe("compact terminal delivery cold process", () => {
|
|
6
|
-
it("adopts a unique-row 132x41 seed and 5000-history patch below the event-loop cap", () => {
|
|
7
|
-
const fixture = fileURLToPath(
|
|
8
|
-
new URL("../test-support/terminal-compact-cold-process.ts", import.meta.url),
|
|
9
|
-
);
|
|
10
|
-
const result = spawnSync(process.execPath, ["--experimental-strip-types", fixture], {
|
|
11
|
-
encoding: "utf8",
|
|
12
|
-
timeout: 30_000,
|
|
13
|
-
});
|
|
14
|
-
expect(result.status, result.stderr).toBe(0);
|
|
15
|
-
const measurement = JSON.parse(result.stdout.trim()) as {
|
|
16
|
-
durationMs: number;
|
|
17
|
-
timerDelayMs: number;
|
|
18
|
-
rssBytes: number;
|
|
19
|
-
heapBytes: number;
|
|
20
|
-
revision: number;
|
|
21
|
-
uniqueHistoryRows: number;
|
|
22
|
-
profiles: Array<Record<string, unknown>>;
|
|
23
|
-
};
|
|
24
|
-
expect(measurement).toMatchObject({ revision: 1, uniqueHistoryRows: 5_000 });
|
|
25
|
-
expect(measurement.rssBytes).toBeLessThan(1_073_741_824);
|
|
26
|
-
expect(measurement.heapBytes).toBeLessThan(536_870_912);
|
|
27
|
-
expect(measurement.durationMs).toBeLessThan(30_000);
|
|
28
|
-
expect(measurement.profiles).toHaveLength(2);
|
|
29
|
-
expect(measurement.profiles).toEqual([
|
|
30
|
-
expect.objectContaining({
|
|
31
|
-
expandedRows: 4_137,
|
|
32
|
-
expandedCells: 546_084,
|
|
33
|
-
schemaTraversals: 1,
|
|
34
|
-
hashTraversals: 1,
|
|
35
|
-
applyTraversals: 0,
|
|
36
|
-
trustedAdoption: true,
|
|
37
|
-
retainedSnapshots: 0,
|
|
38
|
-
}),
|
|
39
|
-
expect.objectContaining({
|
|
40
|
-
expandedRows: 904,
|
|
41
|
-
expandedCells: 119_328,
|
|
42
|
-
schemaTraversals: 1,
|
|
43
|
-
hashTraversals: 1,
|
|
44
|
-
applyTraversals: 1,
|
|
45
|
-
trustedAdoption: true,
|
|
46
|
-
retainedSnapshots: 0,
|
|
47
|
-
}),
|
|
48
|
-
]);
|
|
49
|
-
expect(measurement.timerDelayMs).toBeLessThanOrEqual(33);
|
|
50
|
-
}, 35_000);
|
|
51
|
-
|
|
52
|
-
it("bounds an 8MiB max-width high-run compact seed through final hash", () => {
|
|
53
|
-
const fixture = fileURLToPath(
|
|
54
|
-
new URL("../test-support/terminal-compact-max-cold-process.ts", import.meta.url),
|
|
55
|
-
);
|
|
56
|
-
const result = spawnSync(process.execPath, ["--experimental-strip-types", fixture], {
|
|
57
|
-
encoding: "utf8",
|
|
58
|
-
timeout: 35_000,
|
|
59
|
-
});
|
|
60
|
-
expect(result.status, result.stderr).toBe(0);
|
|
61
|
-
const measurement = JSON.parse(result.stdout.trim()) as {
|
|
62
|
-
timerDelayMs: number;
|
|
63
|
-
maxSliceMs: number;
|
|
64
|
-
maxSliceStage: string;
|
|
65
|
-
representationBytes: number;
|
|
66
|
-
denseRepresentationBytes: number;
|
|
67
|
-
denseRejected: boolean;
|
|
68
|
-
rssBytes: number;
|
|
69
|
-
heapBytes: number;
|
|
70
|
-
revision: number;
|
|
71
|
-
hash: string;
|
|
72
|
-
};
|
|
73
|
-
expect(measurement).toMatchObject({ revision: 0, denseRejected: true });
|
|
74
|
-
expect(measurement.hash).toMatch(/^[0-9a-f]{16}$/u);
|
|
75
|
-
expect(measurement.representationBytes).toBeGreaterThan(8 * 1024 * 1024);
|
|
76
|
-
expect(measurement.denseRepresentationBytes).toBeGreaterThan(14 * 1024 * 1024);
|
|
77
|
-
expect(measurement.rssBytes).toBeLessThan(1_073_741_824);
|
|
78
|
-
expect(measurement.heapBytes).toBeLessThan(536_870_912);
|
|
79
|
-
// This max-width stress case also parses and rejects a deliberately dense
|
|
80
|
-
// 15 MB legacy payload. Keep wall-clock scheduler jitter and the measured
|
|
81
|
-
// CPU slice bounded without conflating this adversarial rejection path with
|
|
82
|
-
// the 33 ms interactive budget enforced by performance qualification.
|
|
83
|
-
expect(measurement.timerDelayMs).toBeLessThanOrEqual(60);
|
|
84
|
-
expect(measurement.maxSliceMs).toBeLessThanOrEqual(150);
|
|
85
|
-
expect(measurement.maxSliceStage).not.toBe("");
|
|
86
|
-
}, 40_000);
|
|
87
|
-
});
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from "vitest";
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
TERMINAL_CONFORMANCE_FIXTURES,
|
|
5
|
-
XTERM_PALETTE,
|
|
6
|
-
XTERM_PALETTE_HEX,
|
|
7
|
-
} from "./terminal-conformance.ts";
|
|
8
|
-
|
|
9
|
-
describe("terminal conformance corpus", () => {
|
|
10
|
-
it("defines one complete, byte-identical xterm palette for every renderer", () => {
|
|
11
|
-
expect(XTERM_PALETTE).toHaveLength(256);
|
|
12
|
-
expect(XTERM_PALETTE_HEX).toHaveLength(256);
|
|
13
|
-
expect(XTERM_PALETTE[0]).toBe(0x000000);
|
|
14
|
-
expect(XTERM_PALETTE[16]).toBe(0x000000);
|
|
15
|
-
expect(XTERM_PALETTE[231]).toBe(0xffffff);
|
|
16
|
-
expect(XTERM_PALETTE[232]).toBe(0x080808);
|
|
17
|
-
expect(XTERM_PALETTE[255]).toBe(0xeeeeee);
|
|
18
|
-
for (let index = 0; index < XTERM_PALETTE.length; index += 1) {
|
|
19
|
-
expect(XTERM_PALETTE_HEX[index]).toBe(
|
|
20
|
-
`#${XTERM_PALETTE[index]!.toString(16).padStart(6, "0")}`,
|
|
21
|
-
);
|
|
22
|
-
}
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
it("keeps fixture ids and asserted cell coordinates unique", () => {
|
|
26
|
-
const ids = TERMINAL_CONFORMANCE_FIXTURES.map((fixture) => fixture.id);
|
|
27
|
-
expect(new Set(ids).size).toBe(ids.length);
|
|
28
|
-
for (const fixture of TERMINAL_CONFORMANCE_FIXTURES) {
|
|
29
|
-
const cells = fixture.cells.map((cell) => `${cell.row}:${cell.column}`);
|
|
30
|
-
expect(new Set(cells).size, fixture.id).toBe(cells.length);
|
|
31
|
-
expect(fixture.writes.join("").length, fixture.id).toBeGreaterThan(0);
|
|
32
|
-
for (const cell of fixture.cells) {
|
|
33
|
-
expect(cell.row).toBeLessThan(fixture.rows);
|
|
34
|
-
expect(cell.column).toBeLessThan(fixture.cols);
|
|
35
|
-
}
|
|
36
|
-
for (const row of fixture.wrappedRows ?? []) {
|
|
37
|
-
expect(row, `${fixture.id} wrapped row`).toBeGreaterThanOrEqual(0);
|
|
38
|
-
expect(row, `${fixture.id} wrapped row`).toBeLessThan(fixture.rows);
|
|
39
|
-
}
|
|
40
|
-
if (fixture.cursor) {
|
|
41
|
-
expect(fixture.cursor.x, `${fixture.id} cursor x`).toBeLessThan(fixture.cols);
|
|
42
|
-
expect(fixture.cursor.y, `${fixture.id} cursor y`).toBeLessThan(fixture.rows);
|
|
43
|
-
}
|
|
44
|
-
if (fixture.historyRows !== undefined)
|
|
45
|
-
expect(fixture.historyRows, `${fixture.id} history`).toBeGreaterThanOrEqual(0);
|
|
46
|
-
}
|
|
47
|
-
});
|
|
48
|
-
});
|
|
@@ -1,167 +0,0 @@
|
|
|
1
|
-
import { execFileSync } from "node:child_process";
|
|
2
|
-
import { mkdtempSync, rmSync } from "node:fs";
|
|
3
|
-
import { tmpdir } from "node:os";
|
|
4
|
-
import { join } from "node:path";
|
|
5
|
-
import { fileURLToPath } from "node:url";
|
|
6
|
-
import { build } from "esbuild";
|
|
7
|
-
import { afterAll, beforeAll, describe, expect, it } from "vitest";
|
|
8
|
-
import {
|
|
9
|
-
applyTerminalReplicaPatch,
|
|
10
|
-
blankTerminalReplicaSnapshot,
|
|
11
|
-
hashTerminalReplicaSnapshot,
|
|
12
|
-
} from "./terminal-replica.ts";
|
|
13
|
-
import {
|
|
14
|
-
decodeVerifiedCompactSemanticTerminalUpdateCooperatively as decode,
|
|
15
|
-
encodeCompactSemanticTerminalUpdate,
|
|
16
|
-
} from "./terminal-delivery.ts";
|
|
17
|
-
|
|
18
|
-
const yieldControl = async () => {};
|
|
19
|
-
|
|
20
|
-
async function decodedBlank() {
|
|
21
|
-
const input = blankTerminalReplicaSnapshot(8, 2);
|
|
22
|
-
return (
|
|
23
|
-
await decode(
|
|
24
|
-
encodeCompactSemanticTerminalUpdate({ frame: "seed", revision: 0, snapshot: input }),
|
|
25
|
-
null,
|
|
26
|
-
hashTerminalReplicaSnapshot(input),
|
|
27
|
-
{ yieldControl },
|
|
28
|
-
)
|
|
29
|
-
).canonicalSnapshot!;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
describe("compact baseline index lifetime", () => {
|
|
33
|
-
it("reuses a row that entered the current baseline after the first index was built", async () => {
|
|
34
|
-
let baseline = await decodedBlank();
|
|
35
|
-
for (let revision = 1; revision <= 3; revision += 1) {
|
|
36
|
-
const row = structuredClone(baseline.grid[0]!);
|
|
37
|
-
row.cells[0]!.grapheme = "X";
|
|
38
|
-
const patch = { rows: [{ index: 1, row }], cursor: { ...baseline.cursor, x: revision } };
|
|
39
|
-
const expected = applyTerminalReplicaPatch(baseline, patch);
|
|
40
|
-
let counts: { allocatedCells: number; reusedRows: number } | undefined;
|
|
41
|
-
const result = await decode(
|
|
42
|
-
encodeCompactSemanticTerminalUpdate({
|
|
43
|
-
frame: "patch",
|
|
44
|
-
baseRevision: revision - 1,
|
|
45
|
-
revision,
|
|
46
|
-
patch,
|
|
47
|
-
}),
|
|
48
|
-
baseline,
|
|
49
|
-
hashTerminalReplicaSnapshot(expected),
|
|
50
|
-
{
|
|
51
|
-
yieldControl,
|
|
52
|
-
onComplete: (profile) => {
|
|
53
|
-
counts = profile;
|
|
54
|
-
},
|
|
55
|
-
},
|
|
56
|
-
);
|
|
57
|
-
expect(result.canonicalSnapshot).toEqual(expected);
|
|
58
|
-
expect(counts).toMatchObject(
|
|
59
|
-
revision === 1
|
|
60
|
-
? { allocatedCells: 8, reusedRows: 0 }
|
|
61
|
-
: { allocatedCells: 0, reusedRows: 1 },
|
|
62
|
-
);
|
|
63
|
-
if (revision > 1) expect(result.canonicalSnapshot!.grid[1]).toBe(baseline.grid[1]);
|
|
64
|
-
baseline = result.canonicalSnapshot!;
|
|
65
|
-
}
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
it("checks history when a same-hash grid candidate has different bytes", async () => {
|
|
69
|
-
const blank = blankTerminalReplicaSnapshot(1, 1);
|
|
70
|
-
const row = (grapheme: string) => ({
|
|
71
|
-
wrapped: false,
|
|
72
|
-
cells: [{ ...blank.grid[0]!.cells[0]!, grapheme }],
|
|
73
|
-
});
|
|
74
|
-
// These encoded rows collide in the raw FNV32 cache, but differ canonically.
|
|
75
|
-
const input = { ...blank, grid: [row("dkzbb9")], history: [row("1mu5745")] };
|
|
76
|
-
const baseline = (
|
|
77
|
-
await decode(
|
|
78
|
-
encodeCompactSemanticTerminalUpdate({ frame: "seed", revision: 0, snapshot: input }),
|
|
79
|
-
null,
|
|
80
|
-
hashTerminalReplicaSnapshot(input),
|
|
81
|
-
{ yieldControl },
|
|
82
|
-
)
|
|
83
|
-
).canonicalSnapshot!;
|
|
84
|
-
const patch = { rows: [{ index: 0, row: baseline.history[0]! }] };
|
|
85
|
-
const expected = applyTerminalReplicaPatch(baseline, patch);
|
|
86
|
-
let counts: { allocatedCells: number; reusedRows: number } | undefined;
|
|
87
|
-
const result = await decode(
|
|
88
|
-
encodeCompactSemanticTerminalUpdate({ frame: "patch", baseRevision: 0, revision: 1, patch }),
|
|
89
|
-
baseline,
|
|
90
|
-
hashTerminalReplicaSnapshot(expected),
|
|
91
|
-
{
|
|
92
|
-
yieldControl,
|
|
93
|
-
onComplete: (profile) => {
|
|
94
|
-
counts = profile;
|
|
95
|
-
},
|
|
96
|
-
},
|
|
97
|
-
);
|
|
98
|
-
expect(result.canonicalSnapshot).toEqual(expected);
|
|
99
|
-
expect(result.canonicalSnapshot!.grid[0]).toBe(baseline.history[0]);
|
|
100
|
-
expect(counts).toMatchObject({ allocatedCells: 0, reusedRows: 1 });
|
|
101
|
-
});
|
|
102
|
-
|
|
103
|
-
// An isolated Node process provides explicit GC without sharing Vitest's
|
|
104
|
-
// retained assertions, module jobs or heap with the weak-reference probe.
|
|
105
|
-
let directory: string;
|
|
106
|
-
let probe: string;
|
|
107
|
-
beforeAll(async () => {
|
|
108
|
-
directory = mkdtempSync(join(tmpdir(), "tmux-compact-lifetime-"));
|
|
109
|
-
probe = join(directory, "probe.mjs");
|
|
110
|
-
const replica = fileURLToPath(new URL("./terminal-replica.ts", import.meta.url));
|
|
111
|
-
const delivery = fileURLToPath(new URL("./terminal-delivery.ts", import.meta.url));
|
|
112
|
-
await build({
|
|
113
|
-
stdin: {
|
|
114
|
-
contents: `
|
|
115
|
-
import {blankTerminalReplicaSnapshot,hashTerminalReplicaSnapshot,applyTerminalReplicaPatch} from ${JSON.stringify(replica)};
|
|
116
|
-
import {encodeCompactSemanticTerminalUpdate,decodeVerifiedCompactSemanticTerminalUpdateCooperatively as decode} from ${JSON.stringify(delivery)};
|
|
117
|
-
const yieldControl=async()=>{};
|
|
118
|
-
const blank=blankTerminalReplicaSnapshot(8,1);
|
|
119
|
-
function row(label){const r=structuredClone(blank.grid[0]);r.cells[0].grapheme=label;return r;}
|
|
120
|
-
async function setup(){
|
|
121
|
-
const chain=process.argv[2]==='chain';
|
|
122
|
-
const input={...blank,grid:[row('A')],history:chain?[row('B')]:Array.from({length:2000},(_,i)=>row('old-'+i))};
|
|
123
|
-
let state=(await decode(encodeCompactSemanticTerminalUpdate({frame:'seed',revision:0,snapshot:input}),null,hashTerminalReplicaSnapshot(input),{yieldControl})).canonicalSnapshot;
|
|
124
|
-
const anchor=state.grid[0];const refs=[];let revision=0;
|
|
125
|
-
async function patch(p){const next=applyTerminalReplicaPatch(state,p);state=(await decode(encodeCompactSemanticTerminalUpdate({frame:'patch',baseRevision:revision,revision:++revision,patch:p}),state,hashTerminalReplicaSnapshot(next),{yieldControl})).canonicalSnapshot;}
|
|
126
|
-
if(chain){
|
|
127
|
-
for(let i=0;i<50;i++){
|
|
128
|
-
await patch({rows:[{index:0,row:state.history[0]}],history:[row('next-'+i)]});
|
|
129
|
-
await patch({rows:[],cursor:{...state.cursor,x:0}});
|
|
130
|
-
refs.push(new WeakRef(state.history[0]));
|
|
131
|
-
}
|
|
132
|
-
}else{
|
|
133
|
-
refs.push(new WeakRef(state.history[1000]));
|
|
134
|
-
await patch({rows:[],historyDelta:{trim:2000,append:[]}});
|
|
135
|
-
}
|
|
136
|
-
return {anchor,refs,current:chain?null:state};
|
|
137
|
-
}
|
|
138
|
-
const result=await setup();
|
|
139
|
-
for(let i=0;i<12;i++){await new Promise(r=>setImmediate(r));global.gc();}
|
|
140
|
-
console.log(JSON.stringify({anchor:result.anchor.cells[0].grapheme,retained:result.refs.filter(r=>r.deref()).length,history:result.current?.history.length??null}));
|
|
141
|
-
`,
|
|
142
|
-
resolveDir: process.cwd(),
|
|
143
|
-
loader: "ts",
|
|
144
|
-
},
|
|
145
|
-
bundle: true,
|
|
146
|
-
platform: "node",
|
|
147
|
-
format: "esm",
|
|
148
|
-
outfile: probe,
|
|
149
|
-
});
|
|
150
|
-
});
|
|
151
|
-
afterAll(() => {
|
|
152
|
-
if (directory) rmSync(directory, { recursive: true, force: true });
|
|
153
|
-
});
|
|
154
|
-
|
|
155
|
-
it.each(["trim", "chain"])(
|
|
156
|
-
"releases obsolete rows after %s while one old row remains alive",
|
|
157
|
-
(mode) => {
|
|
158
|
-
const result = JSON.parse(
|
|
159
|
-
execFileSync(process.execPath, ["--expose-gc", probe, mode], {
|
|
160
|
-
encoding: "utf8",
|
|
161
|
-
timeout: 15_000,
|
|
162
|
-
}),
|
|
163
|
-
);
|
|
164
|
-
expect(result).toEqual({ anchor: "A", retained: 0, history: mode === "trim" ? 0 : null });
|
|
165
|
-
},
|
|
166
|
-
);
|
|
167
|
-
});
|
|
@@ -1,140 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from "vitest";
|
|
2
|
-
import {
|
|
3
|
-
encodeCompactSemanticTerminalUpdate,
|
|
4
|
-
encodeCompactSemanticTerminalUpdateCooperatively,
|
|
5
|
-
terminalSemanticUpdateNeedsCooperativeEncoding,
|
|
6
|
-
TerminalDeliveryStateTooLargeError,
|
|
7
|
-
} from "./terminal-delivery.ts";
|
|
8
|
-
import { blankTerminalReplicaSnapshot } from "./terminal-replica.ts";
|
|
9
|
-
import type { TerminalSemanticDeliveryPayload } from "@tmux-ide/contracts";
|
|
10
|
-
function seed(cols = 128, rows = 64) {
|
|
11
|
-
return {
|
|
12
|
-
frame: "seed" as const,
|
|
13
|
-
revision: 2,
|
|
14
|
-
snapshot: structuredClone(blankTerminalReplicaSnapshot(cols, rows)),
|
|
15
|
-
};
|
|
16
|
-
}
|
|
17
|
-
const yielding = { yieldControl: async () => {} };
|
|
18
|
-
describe("cooperative compact seed encoding", () => {
|
|
19
|
-
it("emits byte-identical dense style, Unicode, wide and history representations", async () => {
|
|
20
|
-
const input = seed();
|
|
21
|
-
for (let y = 0; y < input.snapshot.grid.length; y++) {
|
|
22
|
-
const row = input.snapshot.grid[y]!;
|
|
23
|
-
row.wrapped = y % 2 === 0;
|
|
24
|
-
for (let x = 0; x < row.cells.length; x++)
|
|
25
|
-
row.cells[x] = {
|
|
26
|
-
...row.cells[x]!,
|
|
27
|
-
grapheme: x % 3 === 0 ? '界é🙂\\"\n' : String(x % 10),
|
|
28
|
-
foreground: { kind: "rgb", value: 0x124578 + x },
|
|
29
|
-
background: { kind: "indexed", index: y },
|
|
30
|
-
attributes: x % 256,
|
|
31
|
-
};
|
|
32
|
-
row.cells[0]!.width = 2;
|
|
33
|
-
row.cells[1]!.width = 0;
|
|
34
|
-
}
|
|
35
|
-
input.snapshot.history = input.snapshot.grid.slice(0, 3);
|
|
36
|
-
input.snapshot.placements = [
|
|
37
|
-
{
|
|
38
|
-
id: "widget",
|
|
39
|
-
kind: "plot",
|
|
40
|
-
row: 0,
|
|
41
|
-
column: 0,
|
|
42
|
-
rows: 1,
|
|
43
|
-
columns: 1,
|
|
44
|
-
contentDigest: "digest",
|
|
45
|
-
},
|
|
46
|
-
];
|
|
47
|
-
expect(await encodeCompactSemanticTerminalUpdateCooperatively(input, yielding)).toEqual(
|
|
48
|
-
encodeCompactSemanticTerminalUpdate(input),
|
|
49
|
-
);
|
|
50
|
-
});
|
|
51
|
-
it("joins runs across validation slices and retains exact key order", async () => {
|
|
52
|
-
const input = seed(4096, 2);
|
|
53
|
-
expect(await encodeCompactSemanticTerminalUpdateCooperatively(input, yielding)).toEqual(
|
|
54
|
-
encodeCompactSemanticTerminalUpdate(input),
|
|
55
|
-
);
|
|
56
|
-
});
|
|
57
|
-
it.each(["envelope", "snapshot", "row", "width", "attributes", "color", "cursor", "placement"])(
|
|
58
|
-
"rejects malformed %s with the strict schema",
|
|
59
|
-
async (kind) => {
|
|
60
|
-
const input = seed();
|
|
61
|
-
if (kind === "envelope") Object.assign(input, { unknown: true });
|
|
62
|
-
if (kind === "snapshot") Object.assign(input.snapshot, { unknown: true });
|
|
63
|
-
if (kind === "row") Object.assign(input.snapshot.grid[0]!, { unknown: true });
|
|
64
|
-
if (kind === "width") Object.assign(input.snapshot.grid[0]!.cells[0]!, { width: 3 });
|
|
65
|
-
if (kind === "attributes") input.snapshot.grid[0]!.cells[0]!.attributes = 256;
|
|
66
|
-
if (kind === "color")
|
|
67
|
-
Object.assign(input.snapshot.grid[0]!.cells[0]!, {
|
|
68
|
-
foreground: { kind: "indexed", index: 256 },
|
|
69
|
-
});
|
|
70
|
-
if (kind === "cursor") input.snapshot.cursor.x = -1;
|
|
71
|
-
if (kind === "placement")
|
|
72
|
-
input.snapshot.placements = [
|
|
73
|
-
{ id: "", kind: "x", row: 0, column: 0, rows: 1, columns: 1, contentDigest: "x" },
|
|
74
|
-
];
|
|
75
|
-
expect(() => encodeCompactSemanticTerminalUpdate(input)).toThrow();
|
|
76
|
-
await expect(
|
|
77
|
-
encodeCompactSemanticTerminalUpdateCooperatively(input, yielding),
|
|
78
|
-
).rejects.toThrow();
|
|
79
|
-
},
|
|
80
|
-
);
|
|
81
|
-
it("checks aggregate row/cell and representation limits", async () => {
|
|
82
|
-
const rows = seed();
|
|
83
|
-
rows.snapshot.history = Array.from({ length: 10001 }, () => rows.snapshot.grid[0]!);
|
|
84
|
-
await expect(
|
|
85
|
-
encodeCompactSemanticTerminalUpdateCooperatively(rows, yielding),
|
|
86
|
-
).rejects.toBeInstanceOf(TerminalDeliveryStateTooLargeError);
|
|
87
|
-
const bytes = seed();
|
|
88
|
-
for (const row of bytes.snapshot.grid)
|
|
89
|
-
for (let i = 0; i < row.cells.length; i++)
|
|
90
|
-
row.cells[i]!.grapheme = (i % 2 ? "a" : "b").repeat(4096);
|
|
91
|
-
expect(() => encodeCompactSemanticTerminalUpdate(bytes)).toThrow(
|
|
92
|
-
TerminalDeliveryStateTooLargeError,
|
|
93
|
-
);
|
|
94
|
-
await expect(
|
|
95
|
-
encodeCompactSemanticTerminalUpdateCooperatively(bytes, yielding),
|
|
96
|
-
).rejects.toBeInstanceOf(TerminalDeliveryStateTooLargeError);
|
|
97
|
-
});
|
|
98
|
-
it("yields during validation before reading a whole seed and aborts without bytes", async () => {
|
|
99
|
-
const input = seed();
|
|
100
|
-
let reads = 0;
|
|
101
|
-
for (const row of input.snapshot.grid)
|
|
102
|
-
for (const cell of row.cells)
|
|
103
|
-
Object.defineProperty(cell, "grapheme", {
|
|
104
|
-
enumerable: true,
|
|
105
|
-
get: () => {
|
|
106
|
-
reads++;
|
|
107
|
-
return "";
|
|
108
|
-
},
|
|
109
|
-
});
|
|
110
|
-
const controller = new AbortController(),
|
|
111
|
-
reason = new Error("client retired");
|
|
112
|
-
await expect(
|
|
113
|
-
encodeCompactSemanticTerminalUpdateCooperatively(input, {
|
|
114
|
-
signal: controller.signal,
|
|
115
|
-
yieldControl: async () => {
|
|
116
|
-
expect(reads).toBe(256);
|
|
117
|
-
controller.abort(reason);
|
|
118
|
-
},
|
|
119
|
-
}),
|
|
120
|
-
).rejects.toBe(reason);
|
|
121
|
-
expect(reads).toBe(256);
|
|
122
|
-
});
|
|
123
|
-
it("keeps small updates on ordinary encoding with no task yield", async () => {
|
|
124
|
-
let yields = 0;
|
|
125
|
-
for (const input of [
|
|
126
|
-
seed(4, 2),
|
|
127
|
-
{ frame: "patch", baseRevision: 0, revision: 1, patch: { rows: [] } },
|
|
128
|
-
] satisfies TerminalSemanticDeliveryPayload[]) {
|
|
129
|
-
expect(terminalSemanticUpdateNeedsCooperativeEncoding(input)).toBe(false);
|
|
130
|
-
expect(
|
|
131
|
-
await encodeCompactSemanticTerminalUpdateCooperatively(input, {
|
|
132
|
-
yieldControl: async () => {
|
|
133
|
-
yields++;
|
|
134
|
-
},
|
|
135
|
-
}),
|
|
136
|
-
).toEqual(encodeCompactSemanticTerminalUpdate(input));
|
|
137
|
-
}
|
|
138
|
-
expect(yields).toBe(0);
|
|
139
|
-
});
|
|
140
|
-
});
|
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from "vitest";
|
|
2
|
-
import {
|
|
3
|
-
hashTerminalDeliveryRepresentation,
|
|
4
|
-
splitTerminalDeliveryChunks,
|
|
5
|
-
TerminalDeliveryAssembler,
|
|
6
|
-
} from "./terminal-delivery.ts";
|
|
7
|
-
import type { TerminalDeliveryEnvelope } from "@tmux-ide/contracts";
|
|
8
|
-
|
|
9
|
-
// Independent integer arithmetic oracle for the existing two-lane wire digest.
|
|
10
|
-
function referenceHash(bytes: Uint8Array): string {
|
|
11
|
-
let high = 0x811c9dc5n;
|
|
12
|
-
let low = 0x9e3779b9n;
|
|
13
|
-
for (const byte of bytes) {
|
|
14
|
-
high = ((high ^ BigInt(byte)) * 0x01000193n) & 0xffffffffn;
|
|
15
|
-
low = ((low ^ BigInt(byte)) * 0x85ebca6bn) & 0xffffffffn;
|
|
16
|
-
}
|
|
17
|
-
return high.toString(16).padStart(8, "0") + low.toString(16).padStart(8, "0");
|
|
18
|
-
}
|
|
19
|
-
function slicedBytes(length: number): Uint8Array {
|
|
20
|
-
const backing = Uint8Array.from({ length: length + 19 }, (_, index) => (index * 131 + 17) % 256);
|
|
21
|
-
return backing.subarray(7, length + 7);
|
|
22
|
-
}
|
|
23
|
-
function envelope(bytes: Uint8Array, hash: string): TerminalDeliveryEnvelope {
|
|
24
|
-
return {
|
|
25
|
-
type: "terminal.delivery",
|
|
26
|
-
workspaceName: "hash-parity",
|
|
27
|
-
semanticPaneId: "pane-a",
|
|
28
|
-
generation: "00000000-0000-4000-8000-000000000001",
|
|
29
|
-
incarnation: "00000000-0000-4000-8000-000000000001:0",
|
|
30
|
-
deliveryNonce: "00000000-0000-4000-8000-000000000002",
|
|
31
|
-
transactionId: "00000000-0000-4000-8000-000000000003",
|
|
32
|
-
protocolVersion: 1,
|
|
33
|
-
encoding: "semantic-v1",
|
|
34
|
-
frame: "seed",
|
|
35
|
-
baseRevision: null,
|
|
36
|
-
canonicalRevision: 0,
|
|
37
|
-
canonicalStateHash: "0000000000000000",
|
|
38
|
-
representationHash: hash,
|
|
39
|
-
representationBytes: bytes.byteLength,
|
|
40
|
-
chunkCount: Math.ceil(bytes.byteLength / (256 * 1024)),
|
|
41
|
-
canonicalEquivalent: true,
|
|
42
|
-
history: "complete",
|
|
43
|
-
richPlacements: false,
|
|
44
|
-
};
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
describe("terminal delivery wire hash parity", () => {
|
|
48
|
-
it("preserves unsigned lane arithmetic for empty, sliced and chunk-boundary bytes", () => {
|
|
49
|
-
expect(hashTerminalDeliveryRepresentation(new Uint8Array())).toBe("811c9dc59e3779b9");
|
|
50
|
-
for (const length of [1, 255, 256, 65_537, 262_143, 262_144, 262_145]) {
|
|
51
|
-
const bytes = slicedBytes(length);
|
|
52
|
-
expect(bytes.byteOffset).toBe(7);
|
|
53
|
-
expect(hashTerminalDeliveryRepresentation(bytes)).toBe(referenceHash(bytes));
|
|
54
|
-
}
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
it("preserves incremental assembly across full and partial chunks and refuses corruption", () => {
|
|
58
|
-
const bytes = slicedBytes(2 * 256 * 1024 + 17);
|
|
59
|
-
const expected = referenceHash(bytes);
|
|
60
|
-
const metadata = envelope(bytes, expected);
|
|
61
|
-
const chunks = splitTerminalDeliveryChunks(metadata.transactionId, bytes);
|
|
62
|
-
expect(chunks.map((chunk) => chunk.bytes.length)).toEqual([262_144, 262_144, 17]);
|
|
63
|
-
const valid = new TerminalDeliveryAssembler(metadata);
|
|
64
|
-
for (const chunk of chunks) valid.write(chunk);
|
|
65
|
-
expect(valid.complete()).toEqual(bytes);
|
|
66
|
-
expect(hashTerminalDeliveryRepresentation(valid.complete())).toBe(expected);
|
|
67
|
-
|
|
68
|
-
const corrupt = new TerminalDeliveryAssembler(metadata);
|
|
69
|
-
for (const chunk of chunks) {
|
|
70
|
-
const changed = new Uint8Array(chunk.bytes.length + 9).subarray(9);
|
|
71
|
-
changed.set(chunk.bytes);
|
|
72
|
-
if (chunk.index === 1) changed[changed.length - 1]! ^= 1;
|
|
73
|
-
corrupt.write({ ...chunk, bytes: changed });
|
|
74
|
-
}
|
|
75
|
-
expect(() => corrupt.complete()).toThrow("representation hash mismatch");
|
|
76
|
-
});
|
|
77
|
-
});
|