tmux-ide 2.9.2 → 2.9.3

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.
Files changed (263) hide show
  1. package/README.md +1 -1
  2. package/bin/cli.js +2071 -625
  3. package/package.json +14 -5
  4. package/packages/contracts/src/desktop-host.ts +3 -0
  5. package/packages/contracts/src/saved-machines.ts +19 -0
  6. package/packages/contracts/src/terminal-replica.ts +1 -1
  7. package/packages/core/package.json +3 -2
  8. package/packages/core/src/terminal-delivery.ts +51 -3
  9. package/packages/core/src/terminal-fnv64-wasm.ts +4 -3
  10. package/packages/core/src/terminal-replica-hash-cache.ts +129 -31
  11. package/packages/core/src/terminal-replica-owned-row.ts +27 -0
  12. package/packages/core/src/terminal-replica.ts +13 -28
  13. package/packages/daemon/dist/command-center/daemon-fleet-facts-observer.js +96 -10
  14. package/packages/daemon/dist/command-center/resources/saved-machine-route.js +40 -1
  15. package/packages/daemon/dist/command-center/ws-events.js +5 -24
  16. package/packages/daemon/dist/lib/canonical-daemon-bootstrap.js +8 -0
  17. package/packages/daemon/dist/lib/canonical-daemon.js +28 -2
  18. package/packages/daemon/dist/lib/daemon-embed.js +1 -1
  19. package/packages/daemon/dist/lib/daemon-service-manager.js +122 -0
  20. package/packages/daemon/dist/lib/daemon-service-plan.js +127 -0
  21. package/packages/daemon/dist/lib/daemon-service.js +259 -0
  22. package/packages/daemon/dist/lib/install-origin.js +2 -0
  23. package/packages/daemon/dist/lib/local-fleet-request.js +9 -3
  24. package/packages/daemon/dist/lib/log.js +6 -10
  25. package/packages/daemon/dist/lib/managed-installer-update.js +67 -0
  26. package/packages/daemon/dist/lib/{tui-download-lock.js → private-operation-lock.js} +11 -11
  27. package/packages/daemon/dist/lib/remote-daemon-info.js +3 -2
  28. package/packages/daemon/dist/lib/remote-daemon-lifecycle.js +4 -4
  29. package/packages/daemon/dist/lib/remote-tmux-command.js +10 -0
  30. package/packages/daemon/dist/lib/runtime-namespace.js +28 -16
  31. package/packages/daemon/dist/lib/saved-machines.js +40 -2
  32. package/packages/daemon/dist/lib/ssh-daemon-transport.js +24 -9
  33. package/packages/daemon/dist/lib/tmux-server-owner.js +1 -1
  34. package/packages/daemon/dist/lib/tmux-server-registration.js +21 -3
  35. package/packages/daemon/dist/lib/tui-binary.js +2 -2
  36. package/packages/daemon/dist/lib/update.js +18 -0
  37. package/packages/daemon/dist/lib/workspace-multiplexer-verbs.js +24 -1
  38. package/packages/daemon/dist/machines.js +40 -4
  39. package/packages/daemon/dist/native/TmuxIdeNotifier.app/Contents/Info.plist +2 -2
  40. package/packages/daemon/dist/native/TmuxIdeNotifier.app/Contents/MacOS/tmux-ide-notifier +0 -0
  41. package/packages/daemon/dist/native/TmuxIdeNotifier.app/Contents/Resources/Assets.car +0 -0
  42. package/packages/daemon/dist/native/TmuxIdeNotifier.app/Contents/_CodeSignature/CodeResources +2 -2
  43. package/packages/daemon/dist/terminal/attachments/direct-websocket.js +4 -1
  44. package/packages/daemon/dist/terminal/attachments/native-runtime.js +22 -13
  45. package/packages/daemon/dist/terminal/mirror/mirror-service.js +101 -3
  46. package/packages/daemon/dist/terminal/mirror/registered-window-guard.js +62 -0
  47. package/packages/daemon/dist/terminal/mirror/session-channel.js +75 -4
  48. package/packages/daemon/dist/terminal/mirror/shared-window-index.js +45 -0
  49. package/packages/daemon/dist/terminal/pane-stream/pane-stream-websocket.js +11 -1
  50. package/packages/daemon/dist/terminal/session-runtime/multiplexer-backend.js +1 -0
  51. package/packages/daemon/dist/terminal/session-runtime/registry.js +56 -7
  52. package/packages/daemon/dist/terminal/session-runtime/semantic-mutation-executor.js +3 -1
  53. package/packages/daemon/dist/tui/mirror/dialog-model.js +2 -35
  54. package/packages/daemon/dist/tui/mirror/runtime/application-daemon-authority-owner.js +8 -0
  55. package/packages/daemon/dist/tui/mirror/runtime/application-home-fleet.js +20 -2
  56. package/packages/daemon/dist/tui/mirror/runtime/application-machine-agents.js +7 -1
  57. package/packages/daemon/dist/tui/mirror/runtime/application-machine-authority.js +59 -9
  58. package/packages/daemon/dist/tui/mirror/runtime/application-machine-navigation.js +27 -19
  59. package/packages/daemon/dist/tui/mirror/runtime/application-machine-sidebar.jsx +23 -18
  60. package/packages/daemon/dist/tui/mirror/runtime/application-machine-startup.js +31 -2
  61. package/packages/daemon/dist/tui/mirror/runtime/application-palette-search-owner.js +7 -3
  62. package/packages/daemon/dist/tui/mirror/runtime/application-performance-log.js +3 -0
  63. package/packages/daemon/dist/tui/mirror/runtime/application-terminal-input-ingress.js +146 -2
  64. package/packages/daemon/dist/tui/mirror/runtime/application-terminal-interaction-controller.js +201 -50
  65. package/packages/daemon/dist/tui/mirror/runtime/bounded-performance-record-writer.js +50 -10
  66. package/packages/daemon/dist/tui/mirror/runtime/terminal-fast-lane-renderer-adapter.js +6 -5
  67. package/packages/daemon/dist/tui/mirror/runtime/terminal-pane-input-router.js +3 -0
  68. package/packages/daemon/dist/tui/mirror/runtime/workspace-terminal-fast-lane.js +8 -2
  69. package/packages/daemon/dist/tui/mirror/terminal-text.js +35 -0
  70. package/packages/daemon/dist/tui/mirror/workspace/connection-feedback.js +5 -3
  71. package/packages/daemon/src/command-center/daemon-fleet-facts-observer.ts +100 -10
  72. package/packages/daemon/src/command-center/resources/saved-machine-route.ts +48 -1
  73. package/packages/daemon/src/command-center/ws-events.ts +5 -25
  74. package/packages/daemon/src/lib/canonical-daemon-bootstrap.ts +12 -0
  75. package/packages/daemon/src/lib/canonical-daemon.ts +44 -2
  76. package/packages/daemon/src/lib/daemon-embed.ts +1 -0
  77. package/packages/daemon/src/lib/daemon-service-manager.ts +152 -0
  78. package/packages/daemon/src/lib/daemon-service-plan.ts +153 -0
  79. package/packages/daemon/src/lib/daemon-service.ts +301 -0
  80. package/packages/daemon/src/lib/install-origin.ts +5 -0
  81. package/packages/daemon/src/lib/local-fleet-request.ts +19 -3
  82. package/packages/daemon/src/lib/log.ts +13 -9
  83. package/packages/daemon/src/lib/managed-installer-update.ts +79 -0
  84. package/packages/daemon/src/lib/{tui-download-lock.ts → private-operation-lock.ts} +15 -11
  85. package/packages/daemon/src/lib/remote-daemon-info.ts +3 -3
  86. package/packages/daemon/src/lib/remote-daemon-lifecycle.ts +4 -4
  87. package/packages/daemon/src/lib/remote-tmux-command.ts +12 -0
  88. package/packages/daemon/src/lib/runtime-namespace.ts +27 -18
  89. package/packages/daemon/src/lib/saved-machines.ts +40 -1
  90. package/packages/daemon/src/lib/ssh-daemon-transport.ts +25 -7
  91. package/packages/daemon/src/lib/tmux-server-owner.ts +1 -0
  92. package/packages/daemon/src/lib/tmux-server-registration.ts +21 -3
  93. package/packages/daemon/src/lib/tui-binary.ts +2 -2
  94. package/packages/daemon/src/lib/update.ts +24 -0
  95. package/packages/daemon/src/lib/workspace-multiplexer-verbs.ts +22 -0
  96. package/packages/daemon/src/machines.ts +53 -5
  97. package/packages/daemon/src/terminal/attachments/direct-websocket.ts +8 -2
  98. package/packages/daemon/src/terminal/attachments/native-runtime.ts +28 -13
  99. package/packages/daemon/src/terminal/mirror/mirror-service.ts +105 -3
  100. package/packages/daemon/src/terminal/mirror/registered-window-guard.ts +66 -0
  101. package/packages/daemon/src/terminal/mirror/session-channel.ts +92 -4
  102. package/packages/daemon/src/terminal/mirror/shared-window-index.ts +42 -0
  103. package/packages/daemon/src/terminal/pane-stream/pane-stream-websocket.ts +12 -1
  104. package/packages/daemon/src/terminal/session-runtime/multiplexer-backend.ts +2 -0
  105. package/packages/daemon/src/terminal/session-runtime/registry.ts +70 -8
  106. package/packages/daemon/src/terminal/session-runtime/semantic-mutation-executor.ts +3 -1
  107. package/packages/daemon/src/tui/mirror/dialog-model.ts +2 -32
  108. package/packages/daemon/src/tui/mirror/runtime/application-daemon-authority-owner.ts +8 -0
  109. package/packages/daemon/src/tui/mirror/runtime/application-home-fleet.ts +19 -2
  110. package/packages/daemon/src/tui/mirror/runtime/application-machine-agents.ts +6 -1
  111. package/packages/daemon/src/tui/mirror/runtime/application-machine-authority.ts +60 -11
  112. package/packages/daemon/src/tui/mirror/runtime/application-machine-navigation.ts +39 -33
  113. package/packages/daemon/src/tui/mirror/runtime/application-machine-sidebar.tsx +31 -23
  114. package/packages/daemon/src/tui/mirror/runtime/application-machine-startup.ts +38 -2
  115. package/packages/daemon/src/tui/mirror/runtime/application-palette-search-owner.ts +7 -4
  116. package/packages/daemon/src/tui/mirror/runtime/application-performance-log.ts +3 -0
  117. package/packages/daemon/src/tui/mirror/runtime/application-root-v2.tsx +1 -1
  118. package/packages/daemon/src/tui/mirror/runtime/application-shell-view.tsx +47 -46
  119. package/packages/daemon/src/tui/mirror/runtime/application-terminal-input-ingress.ts +165 -2
  120. package/packages/daemon/src/tui/mirror/runtime/application-terminal-interaction-controller.ts +207 -53
  121. package/packages/daemon/src/tui/mirror/runtime/bounded-performance-record-writer.ts +49 -9
  122. package/packages/daemon/src/tui/mirror/runtime/terminal-fast-lane-renderer-adapter.ts +6 -5
  123. package/packages/daemon/src/tui/mirror/runtime/terminal-pane-input-router.ts +4 -0
  124. package/packages/daemon/src/tui/mirror/runtime/workspace-terminal-fast-lane.ts +8 -3
  125. package/packages/daemon/src/tui/mirror/terminal-text.ts +32 -0
  126. package/packages/daemon/src/tui/mirror/workspace/connection-feedback.ts +6 -3
  127. package/packages/daemon-client/src/fleet-connection-status.ts +10 -1
  128. package/packages/daemon-client/src/workspace-client.ts +4 -1
  129. package/packages/contracts/src/__tests__/actions-contract.test.ts +0 -119
  130. package/packages/contracts/src/__tests__/agent-graph-overlay.test.ts +0 -428
  131. package/packages/contracts/src/__tests__/app-window-mutation.test.ts +0 -51
  132. package/packages/contracts/src/__tests__/app-window-state.test.ts +0 -34
  133. package/packages/contracts/src/__tests__/application-shell.test.ts +0 -645
  134. package/packages/contracts/src/__tests__/automation-operations.test.ts +0 -78
  135. package/packages/contracts/src/__tests__/causal-cell.test.ts +0 -47
  136. package/packages/contracts/src/__tests__/client-view-state.test.ts +0 -115
  137. package/packages/contracts/src/__tests__/cohesion-fixture.test.ts +0 -106
  138. package/packages/contracts/src/__tests__/commands.test.ts +0 -86
  139. package/packages/contracts/src/__tests__/control.test.ts +0 -154
  140. package/packages/contracts/src/__tests__/daemon-events.test.ts +0 -405
  141. package/packages/contracts/src/__tests__/daemon-resources.test.ts +0 -143
  142. package/packages/contracts/src/__tests__/daemon-wire.test.ts +0 -149
  143. package/packages/contracts/src/__tests__/desktop-host.test.ts +0 -269
  144. package/packages/contracts/src/__tests__/desktop-missions.test.ts +0 -215
  145. package/packages/contracts/src/__tests__/experience-conformance.test.ts +0 -153
  146. package/packages/contracts/src/__tests__/experience-kernel-boundary.test.ts +0 -113
  147. package/packages/contracts/src/__tests__/experience-shell.test.ts +0 -65
  148. package/packages/contracts/src/__tests__/fixtures/daemon-wire-v2.json +0 -35
  149. package/packages/contracts/src/__tests__/fixtures/daemon-wire-v3.json +0 -35
  150. package/packages/contracts/src/__tests__/fixtures/daemon-wire-v4.json +0 -35
  151. package/packages/contracts/src/__tests__/fixtures/scoped-receipt.ts +0 -62
  152. package/packages/contracts/src/__tests__/fleet-agent-graph.test.ts +0 -231
  153. package/packages/contracts/src/__tests__/fleet-catalog.test.ts +0 -270
  154. package/packages/contracts/src/__tests__/fleet-lifecycle.test.ts +0 -62
  155. package/packages/contracts/src/__tests__/focus-overlay.test.ts +0 -110
  156. package/packages/contracts/src/__tests__/ide-config.test.ts +0 -64
  157. package/packages/contracts/src/__tests__/interaction-evidence.test.ts +0 -288
  158. package/packages/contracts/src/__tests__/interaction-receipt-v2.test.ts +0 -72
  159. package/packages/contracts/src/__tests__/issue-error.test.ts +0 -78
  160. package/packages/contracts/src/__tests__/mission-projections.test.ts +0 -186
  161. package/packages/contracts/src/__tests__/missions.test.ts +0 -272
  162. package/packages/contracts/src/__tests__/multiplexer-verbs.test.ts +0 -242
  163. package/packages/contracts/src/__tests__/pane-appearance.test.ts +0 -146
  164. package/packages/contracts/src/__tests__/pane-read-result.test.ts +0 -55
  165. package/packages/contracts/src/__tests__/pane-stream.test.ts +0 -536
  166. package/packages/contracts/src/__tests__/pane-widget-marker.test.ts +0 -327
  167. package/packages/contracts/src/__tests__/performance-metrics.test.ts +0 -73
  168. package/packages/contracts/src/__tests__/performance-qualification.test.ts +0 -137
  169. package/packages/contracts/src/__tests__/rich-card-widget.test.ts +0 -29
  170. package/packages/contracts/src/__tests__/session-runtime.test.ts +0 -512
  171. package/packages/contracts/src/__tests__/startup-readiness.test.ts +0 -409
  172. package/packages/contracts/src/__tests__/terminal-attachment-stream.test.ts +0 -72
  173. package/packages/contracts/src/__tests__/terminal-attachments.test.ts +0 -329
  174. package/packages/contracts/src/__tests__/terminal-delivery.test.ts +0 -88
  175. package/packages/contracts/src/__tests__/terminal-runtime-inventory.test.ts +0 -68
  176. package/packages/contracts/src/__tests__/terminals.test.ts +0 -87
  177. package/packages/contracts/src/__tests__/tmux-server-scope.test.ts +0 -166
  178. package/packages/contracts/src/__tests__/transport-contract-loading.test.ts +0 -91
  179. package/packages/contracts/src/__tests__/visual-tokens.test.ts +0 -224
  180. package/packages/contracts/src/__tests__/window-links.test.ts +0 -243
  181. package/packages/contracts/src/__tests__/workspace-changes-resource.test.ts +0 -317
  182. package/packages/contracts/src/__tests__/workspace-changes-view.test.ts +0 -122
  183. package/packages/contracts/src/__tests__/workspace-config.test.ts +0 -294
  184. package/packages/contracts/src/__tests__/workspace-files-resource.test.ts +0 -261
  185. package/packages/contracts/src/__tests__/workspace-files-tree.test.ts +0 -147
  186. package/packages/contracts/src/__tests__/workspace-pane-creation.test.ts +0 -249
  187. package/packages/contracts/src/__tests__/workspace-promotion.test.ts +0 -94
  188. package/packages/contracts/src/__tests__/workspace-resource-identity.test.ts +0 -90
  189. package/packages/contracts/src/daemon-resource-request.test.ts +0 -192
  190. package/packages/contracts/src/native-operation-identity.test.ts +0 -23
  191. package/packages/contracts/src/workspace-admission.test.ts +0 -21
  192. package/packages/contracts/src/workspace-catalog-resource.test.ts +0 -146
  193. package/packages/core/src/agent-provisioning.test.ts +0 -42
  194. package/packages/core/src/application-shell-session.test.ts +0 -105
  195. package/packages/core/src/interaction-evidence.test.ts +0 -134
  196. package/packages/core/src/interaction-flow.test.ts +0 -66
  197. package/packages/core/src/interaction-receipts.test.ts +0 -671
  198. package/packages/core/src/navigator.test.ts +0 -34
  199. package/packages/core/src/optimistic-projection-conformance.test.ts +0 -75
  200. package/packages/core/src/optimistic-projection.test.ts +0 -118
  201. package/packages/core/src/performance-metrics.test.ts +0 -121
  202. package/packages/core/src/performance-qualification.test.ts +0 -283
  203. package/packages/core/src/saved-machines.test.ts +0 -80
  204. package/packages/core/src/terminal-compact-cold.test.ts +0 -87
  205. package/packages/core/src/terminal-conformance.test.ts +0 -48
  206. package/packages/core/src/terminal-delivery-cache-lifetime.test.ts +0 -167
  207. package/packages/core/src/terminal-delivery-encode-cooperative.test.ts +0 -140
  208. package/packages/core/src/terminal-delivery-representation-hash.test.ts +0 -77
  209. package/packages/core/src/terminal-delivery.test.ts +0 -1471
  210. package/packages/core/src/terminal-fnv64-wasm.test.ts +0 -61
  211. package/packages/core/src/terminal-replica-cold.test.ts +0 -31
  212. package/packages/core/src/terminal-replica-cooperative.test.ts +0 -170
  213. package/packages/core/src/terminal-replica-hash-cache.test.ts +0 -283
  214. package/packages/core/src/terminal-replica.test.ts +0 -347
  215. package/packages/core/src/workspace-selection.test.ts +0 -63
  216. package/packages/daemon/dist/__tests__/support.js +0 -33
  217. package/packages/daemon/dist/lib/__tests__/fixtures/workspace-state-writer.js +0 -58
  218. package/packages/daemon/dist/lib/__tests__/installed-recovery-fixture.js +0 -400
  219. package/packages/daemon/dist/terminal/__tests__/MockPtyAdapter.js +0 -182
  220. package/packages/daemon/dist/terminal/mirror/__tests__/scripted-channel.js +0 -98
  221. package/packages/daemon/dist/terminal/mirror/__tests__/simulated-channel.js +0 -156
  222. package/packages/daemon/src/tui/mirror/__snapshots__/activity-surface-renderer.test.tsx.snap +0 -42
  223. package/packages/daemon/src/tui/mirror/__snapshots__/changes-terminal-surface-renderer.test.tsx.snap +0 -267
  224. package/packages/daemon/src/tui/mirror/__snapshots__/home-files-surface-renderer.test.tsx.snap +0 -267
  225. package/packages/daemon/src/tui/mirror/__snapshots__/missions-surface-renderer.test.tsx.snap +0 -134
  226. package/packages/daemon/src/tui/mirror/__snapshots__/recipes-gallery-renderer.test.tsx.snap +0 -141
  227. package/packages/daemon/src/tui/mirror/__snapshots__/shell-chrome-renderer.test.tsx.snap +0 -134
  228. package/packages/daemon/src/tui/mirror/runtime/__snapshots__/application-shell-view-renderer.test.tsx.snap +0 -87
  229. package/packages/daemon/src/tui/mirror/workspace/__snapshots__/agent-terminal-canvas-renderer.test.tsx.snap +0 -348
  230. package/packages/daemon/src/tui/mirror/workspace/__snapshots__/application-shell-renderer.test.tsx.snap +0 -134
  231. package/packages/daemon/src/tui/mirror/workspace/__snapshots__/command-palette-surface-renderer.test.tsx.snap +0 -255
  232. package/packages/daemon/src/tui/mirror/workspace/__snapshots__/pane-frame-renderer.test.tsx.snap +0 -525
  233. package/packages/daemon/src/tui/mirror/workspace/__snapshots__/terminal-pane-header-polish-renderer.test.tsx.snap +0 -31
  234. package/packages/daemon/src/tui/mirror/workspace/__snapshots__/workbench-shell-renderer.test.tsx.snap +0 -134
  235. package/packages/daemon-client/src/application-shell-session.test.ts +0 -196
  236. package/packages/daemon-client/src/automation-client.test.ts +0 -214
  237. package/packages/daemon-client/src/bootstrap-coordinator.test.ts +0 -145
  238. package/packages/daemon-client/src/connection-supervisor.test.ts +0 -109
  239. package/packages/daemon-client/src/direct-application-shell-transport.test.ts +0 -941
  240. package/packages/daemon-client/src/first-latest-coordinator.test.ts +0 -175
  241. package/packages/daemon-client/src/fleet-dial-scheduler.test.ts +0 -114
  242. package/packages/daemon-client/src/fleet-environments.test.ts +0 -40
  243. package/packages/daemon-client/src/generation-bound-store-timers.test.ts +0 -74
  244. package/packages/daemon-client/src/owner-action-client.test.ts +0 -245
  245. package/packages/daemon-client/src/pane-stream-client.test.ts +0 -2841
  246. package/packages/daemon-client/src/pane-stream-clock-calibration.test.ts +0 -207
  247. package/packages/daemon-client/src/pane-stream-loopback-benchmark.test.ts +0 -51
  248. package/packages/daemon-client/src/push-resource-session.test.ts +0 -509
  249. package/packages/daemon-client/src/resource-replica.test.ts +0 -186
  250. package/packages/daemon-client/src/runtime-resource-ledger.test.ts +0 -18
  251. package/packages/daemon-client/src/scoped-tmux-server-transport.test.ts +0 -114
  252. package/packages/daemon-client/src/terminal-fast-lane.test.ts +0 -835
  253. package/packages/daemon-client/src/tmux-server-client.test.ts +0 -279
  254. package/packages/daemon-client/src/tmux-server-interaction-events.test.ts +0 -230
  255. package/packages/daemon-client/src/workspace-catalog-v2.test.ts +0 -109
  256. package/packages/daemon-client/src/workspace-client-boundaries.test.ts +0 -59
  257. package/packages/daemon-client/src/workspace-client-operations.test.ts +0 -96
  258. package/packages/daemon-client/src/workspace-client.test.ts +0 -2912
  259. package/packages/daemon-client/src/workspace-event-supervisor.test.ts +0 -1086
  260. package/packages/daemon-client/src/workspace-pane-client.test.ts +0 -80
  261. package/packages/presentation/src/presentation-contract.test.ts +0 -63
  262. package/packages/tmux-bridge/src/runner.test.ts +0 -614
  263. package/packages/tmux-bridge/src/targeting.test.ts +0 -107
@@ -1,55 +0,0 @@
1
- import { describe, expect, it } from "vitest";
2
- import { SessionRuntimePaneReadResultSchemaZ } from "../session-runtime.ts";
3
- const snapshot = {
4
- verb: "workspace.pane.read",
5
- operationId: "11111111-1111-4111-8111-111111111111",
6
- daemonInstanceId: "22222222-2222-4222-8222-222222222222",
7
- workspaceName: "work",
8
- semanticPaneId: "pane.one",
9
- format: "ansi",
10
- availability: "available",
11
- text: "🙂",
12
- byteCount: 4,
13
- capturedByteCount: 4,
14
- truncated: false,
15
- };
16
- describe("bounded private pane read response", () => {
17
- it("counts UTF8 bytes rather than UTF16 characters", () => {
18
- expect(SessionRuntimePaneReadResultSchemaZ.parse(snapshot).byteCount).toBe(4);
19
- expect(() =>
20
- SessionRuntimePaneReadResultSchemaZ.parse({ ...snapshot, byteCount: 2 }),
21
- ).toThrow();
22
- });
23
- it("rejects above-cap content and dishonest truncation metadata", () => {
24
- expect(() =>
25
- SessionRuntimePaneReadResultSchemaZ.parse({
26
- ...snapshot,
27
- text: "🙂".repeat(5000),
28
- byteCount: 20000,
29
- capturedByteCount: 20000,
30
- }),
31
- ).toThrow();
32
- expect(() =>
33
- SessionRuntimePaneReadResultSchemaZ.parse({
34
- ...snapshot,
35
- capturedByteCount: 8,
36
- truncated: false,
37
- }),
38
- ).toThrow();
39
- });
40
- it("allows content-free replay metadata and forbids replay content", () => {
41
- expect(
42
- SessionRuntimePaneReadResultSchemaZ.parse({
43
- ...snapshot,
44
- availability: "replay-unavailable",
45
- text: null,
46
- }),
47
- ).toMatchObject({ byteCount: 4, text: null });
48
- expect(() =>
49
- SessionRuntimePaneReadResultSchemaZ.parse({
50
- ...snapshot,
51
- availability: "replay-unavailable",
52
- }),
53
- ).toThrow();
54
- });
55
- });
@@ -1,536 +0,0 @@
1
- import { describe, expect, it } from "vitest";
2
- import {
3
- PANE_STREAM_ISSUE_PATH,
4
- PANE_STREAM_MAX_HELD_DELTAS,
5
- PANE_STREAM_MAX_INPUT_TEXT_CHARS,
6
- PANE_STREAM_MAX_LAYOUT_PANES,
7
- PANE_STREAM_MAX_OUTPUT_BASE64_CHARS,
8
- PANE_STREAM_MAX_PANES,
9
- PANE_STREAM_PROTOCOL_VERSION,
10
- PANE_STREAM_REDEEM_PATH,
11
- PANE_STREAM_WEBSOCKET_SUBPROTOCOL,
12
- PaneStreamClientFrameSchemaZ,
13
- PaneStreamConsumedFrameSchemaZ,
14
- PaneStreamInputFrameSchemaZ,
15
- PaneStreamIssueDescriptorSchemaZ,
16
- PaneStreamIssueErrorSchemaZ,
17
- PaneStreamIssueMutationRequestSchemaZ,
18
- PaneStreamIssueResultSchemaZ,
19
- PaneStreamKeyNameSchemaZ,
20
- PaneStreamLeaseRequestSchemaZ,
21
- PaneStreamLoopbackWebSocketUrlSchemaZ,
22
- PaneStreamRedeemFrameSchemaZ,
23
- PaneStreamRedemptionTicketSchemaZ,
24
- PaneStreamSeedBatchFrameSchemaZ,
25
- PaneStreamServerFrameSchemaZ,
26
- } from "../pane-stream.ts";
27
-
28
- const TICKET = `ps2_${"A".repeat(43)}`;
29
- const REQUEST_ID = "7f0f9a7e-9be0-4b6e-a3a3-0a15c9a7e0d1";
30
- const INSTANCE_ID = "3d3f8a52-77aa-4b3e-9a44-2f2f7b1c9d10";
31
- const WS_URL = `ws://127.0.0.1:6070${PANE_STREAM_REDEEM_PATH}`;
32
-
33
- function leaseRequest() {
34
- return {
35
- protocolVersion: PANE_STREAM_PROTOCOL_VERSION,
36
- workspaceName: "workspace.alpha",
37
- panes: ["pane.editor", "pane.mirror.abc123"],
38
- viewerMode: "read-only" as const,
39
- };
40
- }
41
-
42
- function descriptor() {
43
- return {
44
- protocolVersion: PANE_STREAM_PROTOCOL_VERSION,
45
- webSocketUrl: WS_URL,
46
- subprotocol: PANE_STREAM_WEBSOCKET_SUBPROTOCOL,
47
- redemptionTicket: TICKET,
48
- daemonInstanceId: INSTANCE_ID,
49
- requestId: REQUEST_ID,
50
- expiresAt: 90_000,
51
- panes: ["pane.editor"],
52
- effectiveViewerMode: "read-only" as const,
53
- };
54
- }
55
-
56
- describe("pane-stream lease contracts", () => {
57
- it("publishes one shared issue and redemption endpoint authority", () => {
58
- expect(PANE_STREAM_ISSUE_PATH).toBe("/api/v2/terminal/pane-streams/issue");
59
- expect(PANE_STREAM_REDEEM_PATH).toBe("/v2/terminal/pane-streams/redeem");
60
- expect(PANE_STREAM_WEBSOCKET_SUBPROTOCOL).toBe("tmux-ide-pane-stream.v2");
61
- });
62
-
63
- it("accepts a viewport-free enumerated pane set", () => {
64
- const parsed = PaneStreamLeaseRequestSchemaZ.parse(leaseRequest());
65
- expect(parsed.panes).toHaveLength(2);
66
- });
67
-
68
- it("rejects a viewport — mirror streams do not size the source", () => {
69
- expect(
70
- PaneStreamLeaseRequestSchemaZ.safeParse({
71
- ...leaseRequest(),
72
- viewport: { cols: 80, rows: 24 },
73
- }).success,
74
- ).toBe(false);
75
- });
76
-
77
- it("bounds and deduplicates the pane set", () => {
78
- expect(PaneStreamLeaseRequestSchemaZ.safeParse({ ...leaseRequest(), panes: [] }).success).toBe(
79
- false,
80
- );
81
- expect(
82
- PaneStreamLeaseRequestSchemaZ.safeParse({
83
- ...leaseRequest(),
84
- panes: ["pane.editor", "pane.editor"],
85
- }).success,
86
- ).toBe(false);
87
- const tooMany = Array.from({ length: PANE_STREAM_MAX_PANES + 1 }, (_, i) => `pane.p${i}`);
88
- expect(
89
- PaneStreamLeaseRequestSchemaZ.safeParse({ ...leaseRequest(), panes: tooMany }).success,
90
- ).toBe(false);
91
- });
92
-
93
- it("rejects runtime tmux addresses and reserved identities as pane ids", () => {
94
- for (const pane of ["%5", "@3", "$1", "terminal.discovered.x", "__proto__", "pane:colon"]) {
95
- expect(
96
- PaneStreamLeaseRequestSchemaZ.safeParse({ ...leaseRequest(), panes: [pane] }).success,
97
- ).toBe(false);
98
- }
99
- });
100
-
101
- it("rejects renderer-supplied execution, runtime-target, and credential fields", () => {
102
- for (const forbidden of [
103
- { command: "sh -c whoami" },
104
- { cwd: "/tmp" },
105
- { paneId: "%7" },
106
- { tmuxTarget: "owner:@9" },
107
- { authToken: "secret" },
108
- { sessionName: "victim" },
109
- ]) {
110
- expect(
111
- PaneStreamLeaseRequestSchemaZ.safeParse({ ...leaseRequest(), ...forbidden }).success,
112
- ).toBe(false);
113
- }
114
- });
115
-
116
- it("accepts only ps1 tickets", () => {
117
- expect(PaneStreamRedemptionTicketSchemaZ.safeParse(TICKET).success).toBe(true);
118
- for (const invalid of [`ta1_${"A".repeat(43)}`, `ps2_${"A".repeat(42)}`, "ps2_", "ps1"]) {
119
- expect(PaneStreamRedemptionTicketSchemaZ.safeParse(invalid).success).toBe(false);
120
- }
121
- });
122
-
123
- it("pins the WebSocket URL to the canonical loopback redemption endpoint", () => {
124
- expect(PaneStreamLoopbackWebSocketUrlSchemaZ.safeParse(WS_URL).success).toBe(true);
125
- for (const invalid of [
126
- `wss://127.0.0.1:6070${PANE_STREAM_REDEEM_PATH}`,
127
- `ws://example.com:6070${PANE_STREAM_REDEEM_PATH}`,
128
- "ws://127.0.0.1:6070/v1/terminal/attachments/redeem",
129
- `ws://user:pw@127.0.0.1:6070${PANE_STREAM_REDEEM_PATH}`,
130
- `ws://127.0.0.1:6070${PANE_STREAM_REDEEM_PATH}?token=x`,
131
- ]) {
132
- expect(PaneStreamLoopbackWebSocketUrlSchemaZ.safeParse(invalid).success).toBe(false);
133
- }
134
- });
135
-
136
- it("validates the issue descriptor strictly", () => {
137
- expect(PaneStreamIssueDescriptorSchemaZ.parse(descriptor()).panes).toEqual(["pane.editor"]);
138
- expect(
139
- PaneStreamIssueDescriptorSchemaZ.safeParse({ ...descriptor(), ownerToken: "x" }).success,
140
- ).toBe(false);
141
- expect(
142
- PaneStreamIssueDescriptorSchemaZ.safeParse({
143
- ...descriptor(),
144
- redemptionTicket: `ta1_${"A".repeat(43)}`,
145
- }).success,
146
- ).toBe(false);
147
- });
148
-
149
- it("preserves effective copy key modes and leaves older observations unknown", () => {
150
- const layout = {
151
- type: "layout",
152
- semanticWindowId: "window.one",
153
- windowName: "main",
154
- currentWindow: true,
155
- cols: 80,
156
- rows: 24,
157
- zoomed: false,
158
- paneBorderStatus: "off",
159
- panes: [{ pane: "pane.one", left: 0, top: 0, width: 80, height: 24, active: true }],
160
- };
161
- for (const modeKeys of ["emacs", "vi", undefined]) {
162
- expect(PaneStreamServerFrameSchemaZ.parse({ ...layout, modeKeys })).toMatchObject({
163
- modeKeys,
164
- });
165
- }
166
- expect(PaneStreamServerFrameSchemaZ.safeParse({ ...layout, modeKeys: "unknown" }).success).toBe(
167
- false,
168
- );
169
- });
170
-
171
- it("requires layout authority snapshots to be complete and bijective", () => {
172
- const layout = (window: string | null, pane: string | null, currentWindow: boolean) => ({
173
- type: "layout" as const,
174
- semanticWindowId: window,
175
- windowName: "work",
176
- currentWindow,
177
- cols: 80,
178
- rows: 24,
179
- zoomed: false,
180
- paneBorderStatus: "off" as const,
181
- panes: [{ pane, left: 0, top: 0, width: 80, height: 24, active: true }],
182
- });
183
- const snapshot = {
184
- type: "layout-snapshot" as const,
185
- topologyEpoch: 1,
186
- layouts: [layout("window.one", "pane.editor", true)],
187
- windowLinks: {
188
- liveSessionId: `live-session.${"a".repeat(20)}`,
189
- linkRevision: 1,
190
- activeLinkId: `window-link.${"a".repeat(32)}`,
191
- links: [
192
- {
193
- linkId: `window-link.${"a".repeat(32)}`,
194
- semanticWindowId: "window.one",
195
- displayIndex: 0,
196
- },
197
- ],
198
- },
199
- };
200
- expect(PaneStreamServerFrameSchemaZ.safeParse(snapshot).success).toBe(true);
201
- for (const layouts of [
202
- [layout(null, "pane.editor", true)],
203
- [layout("window.one", null, true)],
204
- [layout("window.one", "pane.editor", false)],
205
- [layout("window.one", "pane.editor", true), layout("window.two", "pane.two", true)],
206
- [layout("window.one", "pane.editor", true), layout("window.one", "pane.two", false)],
207
- [layout("window.one", "pane.editor", true), layout("window.two", "pane.editor", false)],
208
- ]) {
209
- expect(PaneStreamServerFrameSchemaZ.safeParse({ ...snapshot, layouts }).success).toBe(false);
210
- }
211
- });
212
-
213
- it("redacts credential material from renderer-facing error reasons", () => {
214
- for (const reason of [
215
- `The redemptionTicket was ${TICKET}`,
216
- "Authorization: Bearer abc",
217
- "owner-token mismatch",
218
- ]) {
219
- expect(
220
- PaneStreamIssueErrorSchemaZ.safeParse({
221
- code: "attachment-unavailable",
222
- reason,
223
- retryable: false,
224
- }).success,
225
- ).toBe(false);
226
- }
227
- expect(
228
- PaneStreamIssueResultSchemaZ.safeParse({
229
- status: "error",
230
- error: {
231
- code: "pane-not-found",
232
- reason: "The requested pane is unavailable.",
233
- retryable: false,
234
- },
235
- }).success,
236
- ).toBe(true);
237
- });
238
-
239
- it("binds the private issue mutation envelope to daemon identity", () => {
240
- expect(
241
- PaneStreamIssueMutationRequestSchemaZ.safeParse({
242
- requestId: REQUEST_ID,
243
- expectedDaemonInstanceId: INSTANCE_ID,
244
- stream: leaseRequest(),
245
- }).success,
246
- ).toBe(true);
247
- expect(
248
- PaneStreamIssueMutationRequestSchemaZ.safeParse({
249
- requestId: REQUEST_ID,
250
- stream: leaseRequest(),
251
- }).success,
252
- ).toBe(false);
253
- });
254
- });
255
-
256
- describe("pane-stream client frames", () => {
257
- it("validates the redemption frame strictly", () => {
258
- const frame = {
259
- type: "redeem",
260
- protocolVersion: PANE_STREAM_PROTOCOL_VERSION,
261
- ticket: TICKET,
262
- requestId: REQUEST_ID,
263
- daemonInstanceId: "daemon-instance-1",
264
- };
265
- expect(PaneStreamRedeemFrameSchemaZ.safeParse(frame).success).toBe(true);
266
- expect(PaneStreamRedeemFrameSchemaZ.safeParse({ ...frame, deliveryAcks: true }).success).toBe(
267
- true,
268
- );
269
- expect(PaneStreamRedeemFrameSchemaZ.safeParse({ ...frame, extra: 1 }).success).toBe(false);
270
- expect(
271
- PaneStreamRedeemFrameSchemaZ.safeParse({ ...frame, ticket: `ta1_${"A".repeat(43)}` }).success,
272
- ).toBe(false);
273
- });
274
-
275
- it("accepts tmux named keys and rejects command-injection shapes", () => {
276
- for (const key of ["Enter", "Escape", "C-c", "M-x", "C-M-a", "F12", "Up", "BSpace", "a", "5"]) {
277
- expect(PaneStreamKeyNameSchemaZ.safeParse(key).success).toBe(true);
278
- }
279
- for (const key of [
280
- "; kill-server",
281
- "Enter Enter",
282
- "$(reboot)",
283
- "'Enter'",
284
- "C-",
285
- "F13",
286
- "Enter;",
287
- "\u0000",
288
- "",
289
- ]) {
290
- expect(PaneStreamKeyNameSchemaZ.safeParse(key).success).toBe(false);
291
- }
292
- });
293
-
294
- it("bounds input text and sequence", () => {
295
- const base = { type: "input", kind: "text", pane: "pane.editor", seq: 1 };
296
- expect(PaneStreamInputFrameSchemaZ.safeParse({ ...base, data: "echo hi" }).success).toBe(true);
297
- expect(
298
- PaneStreamInputFrameSchemaZ.safeParse({
299
- ...base,
300
- data: "x".repeat(PANE_STREAM_MAX_INPUT_TEXT_CHARS + 1),
301
- }).success,
302
- ).toBe(false);
303
- expect(PaneStreamInputFrameSchemaZ.safeParse({ ...base, data: "a\0b" }).success).toBe(false);
304
- expect(PaneStreamInputFrameSchemaZ.safeParse({ ...base, seq: 0, data: "x" }).success).toBe(
305
- false,
306
- );
307
- expect(PaneStreamInputFrameSchemaZ.safeParse({ ...base, pane: "%5", data: "x" }).success).toBe(
308
- false,
309
- );
310
- });
311
-
312
- it("validates consumed frames and the client union", () => {
313
- expect(
314
- PaneStreamConsumedFrameSchemaZ.safeParse({ type: "consumed", pane: "pane.editor", seq: 4 })
315
- .success,
316
- ).toBe(true);
317
- expect(
318
- PaneStreamClientFrameSchemaZ.safeParse({ type: "consumed", pane: "pane.editor", seq: 0 })
319
- .success,
320
- ).toBe(false);
321
- expect(PaneStreamClientFrameSchemaZ.safeParse({ type: "resize", cols: 80 }).success).toBe(
322
- false,
323
- );
324
- });
325
- });
326
-
327
- describe("pane-stream server frames", () => {
328
- it("carries the atomic seed batch as one frame", () => {
329
- const frame = {
330
- type: "seed-batch",
331
- pane: "pane.editor",
332
- seq: 1,
333
- reset: { cols: 120, rows: 40 },
334
- seed: Buffer.from("hello").toString("base64"),
335
- held: [Buffer.from("tail").toString("base64")],
336
- cursor: { x: 4, y: 0 },
337
- };
338
- expect(PaneStreamSeedBatchFrameSchemaZ.safeParse(frame).success).toBe(true);
339
- // Degraded path: no probe answer, no fallback size.
340
- expect(
341
- PaneStreamSeedBatchFrameSchemaZ.safeParse({ ...frame, reset: null, cursor: null }).success,
342
- ).toBe(true);
343
- expect(
344
- PaneStreamSeedBatchFrameSchemaZ.safeParse({
345
- ...frame,
346
- held: Array.from({ length: PANE_STREAM_MAX_HELD_DELTAS + 1 }, () => "aGk="),
347
- }).success,
348
- ).toBe(false);
349
- });
350
-
351
- it("rejects oversized and non-base64 payloads", () => {
352
- const output = (data: string) => ({ type: "output", pane: "pane.editor", seq: 2, data });
353
- expect(PaneStreamServerFrameSchemaZ.safeParse(output("aGVsbG8=")).success).toBe(true);
354
- expect(PaneStreamServerFrameSchemaZ.safeParse(output("not base64!")).success).toBe(false);
355
- expect(
356
- PaneStreamServerFrameSchemaZ.safeParse(
357
- output("A".repeat(PANE_STREAM_MAX_OUTPUT_BASE64_CHARS + 4)),
358
- ).success,
359
- ).toBe(false);
360
- });
361
-
362
- it("speaks semantic identity only — runtime addresses cannot parse", () => {
363
- for (const pane of ["%5", "@3", "$1", "/tmp/pane"]) {
364
- expect(
365
- PaneStreamServerFrameSchemaZ.safeParse({ type: "output", pane, seq: 1, data: "aGk=" })
366
- .success,
367
- ).toBe(false);
368
- expect(
369
- PaneStreamServerFrameSchemaZ.safeParse({
370
- type: "flow",
371
- pane,
372
- seq: 1,
373
- state: "paused",
374
- reason: "backpressure",
375
- }).success,
376
- ).toBe(false);
377
- }
378
- expect(
379
- PaneStreamServerFrameSchemaZ.safeParse({
380
- type: "layout",
381
- semanticWindowId: "@4",
382
- windowName: null,
383
- currentWindow: true,
384
- cols: 200,
385
- rows: 50,
386
- zoomed: false,
387
- panes: [],
388
- }).success,
389
- ).toBe(false);
390
- });
391
-
392
- it("bounds layout frames", () => {
393
- const layout = {
394
- type: "layout",
395
- semanticWindowId: "window.mirror.abc123",
396
- windowName: "editors",
397
- currentWindow: true,
398
- cols: 200,
399
- rows: 50,
400
- zoomed: false,
401
- panes: [
402
- {
403
- pane: "pane.editor",
404
- displayName: "macmon",
405
- displayNameSource: "process",
406
- left: 0,
407
- top: 0,
408
- width: 100,
409
- height: 50,
410
- active: true,
411
- },
412
- { pane: null, left: 100, top: 0, width: 100, height: 50, active: false },
413
- ],
414
- };
415
- expect(PaneStreamServerFrameSchemaZ.safeParse(layout).success).toBe(true);
416
- expect(
417
- PaneStreamServerFrameSchemaZ.safeParse({
418
- ...layout,
419
- panes: [{ ...layout.panes[0], displayNameSource: "guessed" }],
420
- }).success,
421
- ).toBe(false);
422
- expect(
423
- PaneStreamServerFrameSchemaZ.safeParse({
424
- ...layout,
425
- panes: [{ ...layout.panes[0], displayName: "bad\nname" }],
426
- }).success,
427
- ).toBe(false);
428
- expect(
429
- PaneStreamServerFrameSchemaZ.safeParse({
430
- ...layout,
431
- panes: Array.from({ length: PANE_STREAM_MAX_LAYOUT_PANES + 1 }, () => layout.panes[0]),
432
- }).success,
433
- ).toBe(false);
434
- expect(PaneStreamServerFrameSchemaZ.safeParse({ ...layout, windowName: "a\nb" }).success).toBe(
435
- false,
436
- );
437
- });
438
-
439
- it("validates flow, closed, input-ack, and error frames", () => {
440
- for (const frame of [
441
- { type: "flow", pane: "pane.editor", seq: 3, state: "paused", reason: "backpressure" },
442
- { type: "closed", pane: "pane.editor", seq: 4 },
443
- { type: "input-ack", pane: "pane.editor", seq: 9 },
444
- {
445
- type: "error",
446
- protocolVersion: PANE_STREAM_PROTOCOL_VERSION,
447
- code: "ticket-expired",
448
- retryable: true,
449
- },
450
- ]) {
451
- expect(PaneStreamServerFrameSchemaZ.safeParse(frame).success).toBe(true);
452
- }
453
- expect(
454
- PaneStreamServerFrameSchemaZ.safeParse({
455
- type: "flow",
456
- pane: "pane.editor",
457
- seq: 1,
458
- state: "gone",
459
- reason: "backpressure",
460
- }).success,
461
- ).toBe(false);
462
- expect(PaneStreamServerFrameSchemaZ.safeParse({ type: "shutdown" }).success).toBe(false);
463
- });
464
-
465
- it("audits a representative wire transcript for runtime ids and reserved keys", () => {
466
- const transcript = [
467
- {
468
- type: "ready",
469
- protocolVersion: PANE_STREAM_PROTOCOL_VERSION,
470
- daemonInstanceId: "daemon-instance-1",
471
- requestId: REQUEST_ID,
472
- panes: ["pane.editor"],
473
- effectiveViewerMode: "interactive",
474
- },
475
- {
476
- type: "seed-batch",
477
- pane: "pane.editor",
478
- seq: 1,
479
- reset: { cols: 80, rows: 24 },
480
- seed: "aGVsbG8=",
481
- held: [],
482
- cursor: { x: 0, y: 0 },
483
- },
484
- { type: "output", pane: "pane.editor", seq: 2, data: "d29ybGQ=" },
485
- ];
486
- for (const frame of transcript) {
487
- const parsed = PaneStreamServerFrameSchemaZ.parse(frame);
488
- // Structural fields never carry runtime tmux addresses or paths. The
489
- // base64 payload fields are excluded: pane CONTENT is user bytes.
490
- const { ...structural } = parsed as Record<string, unknown>;
491
- delete structural.seed;
492
- delete structural.held;
493
- delete structural.data;
494
- const encoded = JSON.stringify(structural);
495
- expect(encoded).not.toMatch(/[%@$][0-9]/u);
496
- expect(encoded).not.toMatch(/\/(?:tmp|Users|home)\//u);
497
- expect(Object.keys(structural)).not.toContain("__proto__");
498
- }
499
- });
500
- });
501
-
502
- describe("window-scoped viewport frames", () => {
503
- const frame = {
504
- type: "viewport",
505
- seq: 1,
506
- cols: 120,
507
- rows: 40,
508
- authorityLease: {
509
- generation: INSTANCE_ID,
510
- session: "alpha",
511
- clientId: "web:test",
512
- authority: "geometry",
513
- token: REQUEST_ID,
514
- revision: 1,
515
- },
516
- };
517
- it("accepts an optional semantic window while preserving legacy session fit", () => {
518
- expect(PaneStreamClientFrameSchemaZ.safeParse(frame).success).toBe(true);
519
- expect(
520
- PaneStreamClientFrameSchemaZ.safeParse({ ...frame, semanticWindowId: "window.main" }).success,
521
- ).toBe(true);
522
- });
523
- it("rejects raw tmux addresses and non-geometry authority", () => {
524
- for (const semanticWindowId of ["@1", "window; kill-server", "", "terminal.discovered.one"])
525
- expect(PaneStreamClientFrameSchemaZ.safeParse({ ...frame, semanticWindowId }).success).toBe(
526
- false,
527
- );
528
- expect(
529
- PaneStreamClientFrameSchemaZ.safeParse({
530
- ...frame,
531
- semanticWindowId: "window.main",
532
- authorityLease: { ...frame.authorityLease, authority: "input" },
533
- }).success,
534
- ).toBe(false);
535
- });
536
- });