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,279 +0,0 @@
1
- import { describe, expect, it, mock } from "bun:test";
2
- import {
3
- PANE_STREAM_PROTOCOL_VERSION,
4
- PANE_STREAM_REDEEM_PATH,
5
- PANE_STREAM_WEBSOCKET_SUBPROTOCOL,
6
- tmuxServerPaneStreamPath,
7
- } from "@tmux-ide/contracts";
8
- import {
9
- createTmuxServerClient,
10
- listTmuxServers,
11
- registerTmuxServer,
12
- removeTmuxServer,
13
- } from "./tmux-server-client.ts";
14
- const scope = {
15
- serverId: `tmux-server.${"a".repeat(32)}`,
16
- generation: "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa",
17
- };
18
- const other = { ...scope, serverId: `tmux-server.${"b".repeat(32)}` };
19
- const requestId = "bbbbbbbb-bbbb-4bbb-8bbb-bbbbbbbbbbbb";
20
- const base = {
21
- baseUrl: "http://127.0.0.1:4000",
22
- ownerToken: "owner",
23
- hostClientId: "client",
24
- origin: "http://localhost:3000",
25
- };
26
- const sessions = (server = scope) => ({
27
- version: 1,
28
- server,
29
- sessions: [
30
- {
31
- liveSessionId: `live-session.${"a".repeat(20)}`,
32
- sessionName: "main",
33
- workspaceName: "alias",
34
- paneCount: 1,
35
- },
36
- ],
37
- });
38
- const stream = {
39
- protocolVersion: PANE_STREAM_PROTOCOL_VERSION,
40
- workspaceName: "main",
41
- panes: ["pane.one"],
42
- viewerMode: "interactive" as const,
43
- };
44
- const issued = () => ({
45
- status: "issued",
46
- descriptor: {
47
- protocolVersion: PANE_STREAM_PROTOCOL_VERSION,
48
- webSocketUrl: `ws://127.0.0.1:4000${tmuxServerPaneStreamPath(scope)}`,
49
- subprotocol: PANE_STREAM_WEBSOCKET_SUBPROTOCOL,
50
- redemptionTicket: `ps2_${"a".repeat(43)}`,
51
- daemonInstanceId: scope.generation,
52
- requestId,
53
- expiresAt: Date.now() + 10000,
54
- panes: ["pane.one"],
55
- effectiveViewerMode: "interactive",
56
- },
57
- });
58
-
59
- describe("explicit tmux server SDK client", () => {
60
- it("validates versioned server listing without fallback", async () => {
61
- const fetcher = mock(async (url: string | URL | Request, init?: RequestInit) => {
62
- expect(String(url)).toBe(`${base.baseUrl}/api/v1/tmux-servers`);
63
- expect(init?.headers).toMatchObject({ Authorization: "Bearer owner" });
64
- return Response.json({
65
- version: 1,
66
- servers: [{ ...scope, state: "online", label: "default" }],
67
- });
68
- });
69
- expect(
70
- (await listTmuxServers({ ...base, fetch: fetcher as typeof fetch })).servers,
71
- ).toHaveLength(1);
72
- await expect(
73
- listTmuxServers({
74
- ...base,
75
- fetch: mock(async () => Response.json({ version: 2, servers: [] })) as typeof fetch,
76
- }),
77
- ).rejects.toThrow();
78
- });
79
-
80
- it("binds copied inputs and cache keys to an immutable exact scope", async () => {
81
- const input = { ...scope };
82
- const fetcher = mock(async (url: string | URL | Request) => {
83
- expect(String(url)).toContain(`/${scope.serverId}/${scope.generation}/sessions`);
84
- return Response.json(sessions());
85
- });
86
- const client = createTmuxServerClient({ ...base, fetch: fetcher as typeof fetch }, input);
87
- input.serverId = other.serverId;
88
- expect((await client.sessions()).server).toEqual(scope);
89
- expect(Object.isFrozen(client.scope)).toBe(true);
90
- expect(client.cacheKey("pane", "%0")).not.toBe(
91
- createTmuxServerClient(base, other).cacheKey("pane", "%0"),
92
- );
93
- });
94
-
95
- it("rejects scope mismatches and stale HTTP refusal without retries", async () => {
96
- const fetcher = mock(async () => Response.json(sessions(other)));
97
- await expect(
98
- createTmuxServerClient({ ...base, fetch: fetcher as typeof fetch }, scope).sessions(),
99
- ).rejects.toMatchObject({ code: "scope-mismatch" });
100
- const refused = mock(async () =>
101
- Response.json({ error: { code: "stale-generation" } }, { status: 409 }),
102
- );
103
- await expect(
104
- createTmuxServerClient({ ...base, fetch: refused as typeof fetch }, scope).sessions(),
105
- ).rejects.toMatchObject({ status: 409 });
106
- expect(refused).toHaveBeenCalledTimes(1);
107
- });
108
-
109
- it("drops an old selection's late response after disposal", async () => {
110
- let resolve!: (response: Response) => void;
111
- const pending = new Promise<Response>((done) => {
112
- resolve = done;
113
- });
114
- const fetcher = mock(async () => pending);
115
- const client = createTmuxServerClient({ ...base, fetch: fetcher as typeof fetch }, scope);
116
- const result = client.sessions();
117
- client.dispose();
118
- resolve(Response.json(sessions()));
119
- await expect(result).rejects.toMatchObject({ code: "disposed" });
120
- await expect(client.sessions()).rejects.toMatchObject({ code: "disposed" });
121
- expect(fetcher).toHaveBeenCalledTimes(1);
122
- });
123
-
124
- it("uses explicit owner authority for passive fleet close without a controller principal", async () => {
125
- const fetcher = mock(async (_url: RequestInfo | URL, init?: RequestInit) => {
126
- expect(new Headers(init?.headers).has("X-Tmux-Ide-Host-Client-Id")).toBe(false);
127
- expect(new Headers(init?.headers).get("Authorization")).toBe("Bearer owner");
128
- return Response.json({
129
- operationId: requestId,
130
- daemonInstanceId: scope.generation,
131
- workspaceName: "same",
132
- verb: "workspace.session.kill",
133
- outcome: "applied",
134
- });
135
- });
136
- await createTmuxServerClient({ ...base, fetch: fetcher as typeof fetch }, scope).mutate(
137
- requestId,
138
- {
139
- verb: "workspace.session.kill",
140
- workspaceName: "same",
141
- fleetTarget: {
142
- daemonInstanceId: scope.generation,
143
- liveSessionId: `live-session.${"a".repeat(20)}`,
144
- sessionName: "same",
145
- },
146
- },
147
- );
148
- expect(fetcher).toHaveBeenCalledTimes(1);
149
- });
150
-
151
- it("sends owner-scoped mutations and verifies generation and operation echoes", async () => {
152
- const fetcher = mock(async (_url: string | URL | Request, init?: RequestInit) => {
153
- const body = JSON.parse(String(init?.body));
154
- expect(body.expectedDaemonInstanceId).toBe(scope.generation);
155
- return Response.json({
156
- operationId: body.operationId,
157
- daemonInstanceId: scope.generation,
158
- outcome: "applied",
159
- workspaceName: "main",
160
- verb: "workspace.pane.select",
161
- semanticPaneId: "pane.one",
162
- });
163
- });
164
- const client = createTmuxServerClient({ ...base, fetch: fetcher as typeof fetch }, scope);
165
- const result = await client.mutate(requestId, {
166
- verb: "workspace.pane.select",
167
- workspaceName: "main",
168
- semanticPaneId: "pane.one",
169
- });
170
- expect(result.daemonInstanceId).toBe(scope.generation);
171
- });
172
-
173
- it("sends exact issue headers and validates scoped redemption", async () => {
174
- const fetcher = mock(async (url: string | URL | Request, init?: RequestInit) => {
175
- expect(String(url)).toEndWith(`/${scope.serverId}/${scope.generation}/pane-streams/issue`);
176
- expect(init?.headers).toMatchObject({
177
- Authorization: "Bearer owner",
178
- Origin: base.origin,
179
- "X-Tmux-Ide-Request-Id": requestId,
180
- "X-Tmux-Ide-Expected-Daemon-Instance-Id": scope.generation,
181
- "X-Tmux-Ide-Host-Client-Id": "client",
182
- });
183
- return Response.json(issued());
184
- });
185
- expect(
186
- (
187
- await createTmuxServerClient(
188
- { ...base, fetch: fetcher as typeof fetch },
189
- scope,
190
- ).issuePaneStream(requestId, stream)
191
- ).status,
192
- ).toBe("issued");
193
- const wrong = issued();
194
- wrong.descriptor.webSocketUrl = `ws://127.0.0.1:4000${tmuxServerPaneStreamPath(other)}`;
195
- await expect(
196
- createTmuxServerClient(
197
- { ...base, fetch: mock(async () => Response.json(wrong)) as typeof fetch },
198
- scope,
199
- ).issuePaneStream(requestId, stream),
200
- ).rejects.toMatchObject({ code: "scope-mismatch" });
201
- });
202
-
203
- it("rejects inventories from the wrong workspace", async () => {
204
- const fetcher = mock(async () =>
205
- Response.json({
206
- version: 1,
207
- server: scope,
208
- resource: {
209
- workspaceName: "other",
210
- workspaceId: "workspace.0123456789abcdefabcd",
211
- sessionId: "session.0123456789abcdefabcd",
212
- resourceRevision: 0,
213
- semanticPaneIds: ["pane.one"],
214
- },
215
- }),
216
- );
217
- await expect(
218
- createTmuxServerClient({ ...base, fetch: fetcher as typeof fetch }, scope).inventory("main"),
219
- ).rejects.toMatchObject({ code: "scope-mismatch" });
220
- });
221
- });
222
-
223
- describe("server registration and adopted default", () => {
224
- it("passes remote selector intent unchanged and removes by opaque registration", async () => {
225
- const calls: Array<{ url: string; init?: RequestInit }> = [];
226
- const fetcher = mock(async (url: string | URL | Request, init?: RequestInit) => {
227
- calls.push({ url: String(url), init });
228
- return Response.json(
229
- init?.method === "DELETE"
230
- ? { removed: true }
231
- : { ...scope, label: "remote", state: "online" },
232
- );
233
- });
234
- const options = { ...base, fetch: fetcher as typeof fetch };
235
- await registerTmuxServer(options, {
236
- label: "remote",
237
- selector: { kind: "path", path: "/remote/socket" },
238
- });
239
- expect(JSON.parse(String(calls[0]?.init?.body)).selector).toEqual({
240
- kind: "path",
241
- path: "/remote/socket",
242
- });
243
- await removeTmuxServer(options, scope.serverId);
244
- expect(calls[1]?.init?.method).toBe("DELETE");
245
- expect(calls[1]?.url).toEndWith(`/${scope.serverId}`);
246
- await expect(removeTmuxServer(options, "../default")).rejects.toThrow();
247
- expect(fetcher).toHaveBeenCalledTimes(2);
248
- });
249
-
250
- it("accepts default redemption only with an exact generation and request echo", async () => {
251
- const response = issued();
252
- response.descriptor.webSocketUrl = `ws://127.0.0.1:4000${PANE_STREAM_REDEEM_PATH}`;
253
- const fetcher = mock(async () => Response.json(response));
254
- const client = createTmuxServerClient({ ...base, fetch: fetcher as typeof fetch }, scope);
255
- expect((await client.issuePaneStream(requestId, stream)).status).toBe("issued");
256
- response.descriptor.daemonInstanceId = requestId;
257
- await expect(client.issuePaneStream(requestId, stream)).rejects.toMatchObject({
258
- code: "scope-mismatch",
259
- });
260
- });
261
-
262
- it("preserves authoritative workspace aliases and unavailable collisions", async () => {
263
- const response = sessions();
264
- const client = createTmuxServerClient(
265
- { ...base, fetch: mock(async () => Response.json(response)) as typeof fetch },
266
- scope,
267
- );
268
- expect((await client.sessions()).sessions[0]?.workspaceName).toBe("alias");
269
- const unavailable = {
270
- ...response,
271
- sessions: response.sessions.map((session) => ({ ...session, workspaceName: null })),
272
- };
273
- const otherClient = createTmuxServerClient(
274
- { ...base, fetch: mock(async () => Response.json(unavailable)) as typeof fetch },
275
- scope,
276
- );
277
- expect((await otherClient.sessions()).sessions[0]?.workspaceName).toBeNull();
278
- });
279
- });
@@ -1,230 +0,0 @@
1
- import { describe, expect, it } from "bun:test";
2
- import { subscribeTmuxServerInteractions } from "./tmux-server-interaction-events.ts";
3
- const server = {
4
- serverId: `tmux-server.${"a".repeat(32)}`,
5
- generation: "11111111-1111-4111-8111-111111111111",
6
- };
7
- const observationStatus = {
8
- schemaVersion: 1,
9
- environmentId: "00000000-0000-4000-8000-000000000001",
10
- serverScope: server,
11
- method: "unavailable",
12
- capabilityVersion: null,
13
- commands: [],
14
- effects: [],
15
- coverage: "unavailable",
16
- cursor: null,
17
- lastGap: null,
18
- droppedCount: "0",
19
- };
20
- const ready = { version: 1, server, type: "ready", after: 0, observationStatus };
21
- const receipt = {
22
- type: "interaction.receipt",
23
- sequence: 1,
24
- operationId: "afbc7eaf-604a-4117-8296-aef44b889af1",
25
- origin: "external",
26
- workspaceName: "same",
27
- sourceSemanticPaneId: null,
28
- target: { kind: "pane", semanticPaneId: "pane.same" },
29
- operationKind: "workspace.pane.send",
30
- phase: "observed",
31
- summary: { operationKind: "workspace.pane.send", observedOnly: true },
32
- proof: { operationKind: "workspace.pane.send", observed: true, semanticPaneId: "pane.same" },
33
- at: "2026-09-28T00:00:00.000Z",
34
- resourceRevision: null,
35
- evidence: {
36
- schemaVersion: 1,
37
- interactionId: "afbc7eaf-604a-4117-8296-aef44b889af1",
38
- revision: 0,
39
- endpoints: {
40
- destination: {
41
- kind: "pane",
42
- environmentId: observationStatus.environmentId,
43
- serverScope: server,
44
- paneLifetimeId: "00000000-0000-4000-8000-000000000003",
45
- workspaceName: "same",
46
- semanticPaneId: "pane.same",
47
- },
48
- source: null,
49
- },
50
- actor: { kind: "unknown", reason: "stock-hook" },
51
- observation: { kind: "stock-hook", command: "send-keys" },
52
- effect: { kind: "unknown" },
53
- occurredAt: null,
54
- timeBasis: "unknown",
55
- receivedAt: "2026-09-28T00:00:00.000Z",
56
- },
57
- };
58
- const batch = {
59
- version: 1,
60
- server,
61
- type: "batch",
62
- after: 0,
63
- cursor: 1,
64
- gap: null,
65
- receipts: [receipt],
66
- };
67
- function fake(frames: unknown[]) {
68
- return (async () =>
69
- new Response(
70
- new ReadableStream({
71
- start(c) {
72
- for (const f of frames)
73
- c.enqueue(new TextEncoder().encode(`data: ${JSON.stringify(f)}\n\n`));
74
- c.close();
75
- },
76
- }),
77
- )) as typeof fetch;
78
- }
79
- function subscribe(frames: unknown[], onBatch = () => {}) {
80
- return subscribeTmuxServerInteractions({
81
- baseUrl: "http://localhost",
82
- ownerToken: "token",
83
- server,
84
- fetch: fake(frames),
85
- onBatch,
86
- });
87
- }
88
- describe("interaction subscriber fences", () => {
89
- it("rejects status scope mismatch and missing initial coverage", async () => {
90
- for (const frames of [
91
- [{ ...ready, observationStatus: undefined }],
92
- [
93
- ready,
94
- {
95
- version: 1,
96
- server,
97
- type: "status",
98
- observationStatus: {
99
- ...observationStatus,
100
- serverScope: { ...server, generation: "22222222-2222-4222-8222-222222222222" },
101
- },
102
- },
103
- ],
104
- ]) {
105
- const stream = subscribe(frames);
106
- stream.ready.catch(() => {});
107
- await expect(stream.done).rejects.toThrow();
108
- }
109
- });
110
- it("rejects evidence destination scope different from its enclosing stream", async () => {
111
- const foreign = structuredClone(batch);
112
- foreign.receipts[0]!.evidence.endpoints.destination.serverScope.generation =
113
- "22222222-2222-4222-8222-222222222222";
114
- const stream = subscribe([ready, foreign]);
115
- await stream.ready;
116
- await expect(stream.done).rejects.toThrow();
117
- });
118
- it("delivers status-only frames without advancing receipt cursor", async () => {
119
- const seen: string[] = [];
120
- const stream = subscribeTmuxServerInteractions({
121
- baseUrl: "http://localhost",
122
- ownerToken: "token",
123
- server,
124
- fetch: fake([
125
- ready,
126
- {
127
- version: 1,
128
- server,
129
- type: "status",
130
- observationStatus: {
131
- ...observationStatus,
132
- method: "stock-hooks",
133
- capabilityVersion: 1,
134
- coverage: "partial",
135
- commands: ["send-keys", "capture-pane"],
136
- },
137
- },
138
- ]),
139
- onBatch: () => {
140
- throw Error("Unexpected batch");
141
- },
142
- onStatus: (status) => seen.push(status.method),
143
- });
144
- await stream.ready;
145
- await stream.done.catch(() => {});
146
- expect(seen).toEqual(["unavailable", "stock-hooks"]);
147
- expect(stream.getCursor().cursor).toBe(0);
148
- });
149
- it("closes while a consumer is stalled without acknowledging its batch", async () => {
150
- let started!: () => void;
151
- const called = new Promise<void>((resolve) => {
152
- started = resolve;
153
- });
154
- let consumerSignal: AbortSignal | undefined;
155
- const stream = subscribeTmuxServerInteractions({
156
- baseUrl: "http://localhost",
157
- ownerToken: "token",
158
- server,
159
- fetch: fake([ready, batch]),
160
- onBatch: (_batch, signal) => {
161
- consumerSignal = signal;
162
- started();
163
- return new Promise<void>(() => {});
164
- },
165
- });
166
- await called;
167
- stream.close();
168
- await stream.done;
169
- expect(consumerSignal?.aborted).toBe(true);
170
- expect(stream.getCursor().cursor).toBe(0);
171
- });
172
- it("rejects scoped resume reuse before making a request", () => {
173
- expect(() =>
174
- subscribeTmuxServerInteractions({
175
- baseUrl: "http://localhost",
176
- ownerToken: "token",
177
- server,
178
- resume: {
179
- server: { ...server, generation: "22222222-2222-4222-8222-222222222222" },
180
- cursor: 0,
181
- },
182
- onBatch: () => {},
183
- }),
184
- ).toThrow("another owner");
185
- });
186
- it.each(["owner", "generation", "repeated ready", "version", "before ready", "regression"])(
187
- "rejects %s frames",
188
- async (kind) => {
189
- let frames: unknown[] = [ready];
190
- if (kind === "owner")
191
- frames.push({ ...batch, server: { ...server, serverId: `tmux-server.${"b".repeat(32)}` } });
192
- if (kind === "generation")
193
- frames.push({
194
- ...batch,
195
- server: { ...server, generation: "22222222-2222-4222-8222-222222222222" },
196
- });
197
- if (kind === "repeated ready") frames.push(ready);
198
- if (kind === "version") frames.push({ ...batch, version: 2 });
199
- if (kind === "before ready") frames = [batch];
200
- if (kind === "regression") frames.push({ ...batch, cursor: 0 });
201
- let calls = 0;
202
- const stream = subscribe(frames, () => {
203
- calls++;
204
- });
205
- await expect(stream.done).rejects.toThrow();
206
- expect(calls).toBe(0);
207
- },
208
- );
209
- it("rejects repeated receipts without delivering them twice", async () => {
210
- let calls = 0;
211
- const stream = subscribe([ready, batch, batch], () => {
212
- calls++;
213
- });
214
- await expect(stream.done).rejects.toThrow("Repeated");
215
- expect(calls).toBe(1);
216
- expect(stream.getCursor().cursor).toBe(1);
217
- });
218
- it("retains only acknowledged callback progress for reconnect", async () => {
219
- const stream = subscribe([ready, batch], () => {
220
- throw Error("consumer failed");
221
- });
222
- await expect(stream.done).rejects.toThrow("consumer failed");
223
- expect(stream.getCursor().cursor).toBe(0);
224
- });
225
- it("rejects a fabricated gap and noncontiguous receipts", async () => {
226
- const stream = subscribe([ready, { ...batch, gap: { from: 2, through: 2 } }]);
227
- await expect(stream.done).rejects.toThrow();
228
- expect(stream.getCursor().cursor).toBe(0);
229
- });
230
- });
@@ -1,109 +0,0 @@
1
- import { describe, expect, it } from "bun:test";
2
-
3
- import {
4
- initialWorkspaceCatalogV2State,
5
- replaceWorkspaceCatalogV2,
6
- } from "./workspace-catalog-v2.ts";
7
-
8
- const daemon = (instanceId: string) => ({
9
- protocolVersion: 1,
10
- productVersion: "test",
11
- instanceId,
12
- startedAt: "2026-08-12T00:00:00.000Z",
13
- });
14
- const retiredFleetSessionId = "session.aaaaaaaaaaaaaaaaaaaa";
15
- const sameFleetSessionId = "session.bbbbbbbbbbbbbbbbbbbb";
16
-
17
- describe("workspace catalog V2 state", () => {
18
- it("keeps stopped durable intent separate from observed live tmux sessions", () => {
19
- const state = replaceWorkspaceCatalogV2(initialWorkspaceCatalogV2State(), {
20
- version: 2,
21
- daemon: daemon("11111111-1111-4111-8111-111111111111"),
22
- intents: [
23
- {
24
- workspaceName: "saved-workspace",
25
- sessionName: "saved-session",
26
- source: "workspace",
27
- availability: "live",
28
- },
29
- ],
30
- liveSessions: [],
31
- });
32
-
33
- expect(state.intents).toEqual([
34
- expect.objectContaining({ workspaceName: "saved-workspace", availability: "stopped" }),
35
- ]);
36
- expect(state.liveSessions).toEqual([]);
37
- });
38
-
39
- it("replaces rather than merges state across daemon generations", () => {
40
- const first = replaceWorkspaceCatalogV2(initialWorkspaceCatalogV2State(), {
41
- version: 2,
42
- daemon: daemon("11111111-1111-4111-8111-111111111111"),
43
- intents: [
44
- {
45
- workspaceName: "retired",
46
- sessionName: "retired",
47
- source: "project",
48
- availability: "live",
49
- },
50
- ],
51
- liveSessions: [
52
- { sessionName: "retired", fleetSessionId: retiredFleetSessionId, paneCount: 2 },
53
- ],
54
- });
55
- const replacement = replaceWorkspaceCatalogV2(first, {
56
- version: 2,
57
- daemon: daemon("22222222-2222-4222-8222-222222222222"),
58
- intents: [],
59
- liveSessions: [],
60
- });
61
-
62
- expect(replacement).toEqual({
63
- daemonInstanceId: "22222222-2222-4222-8222-222222222222",
64
- intents: [],
65
- liveSessions: [],
66
- });
67
- });
68
-
69
- it("rejects duplicate observed session identities", () => {
70
- expect(() =>
71
- replaceWorkspaceCatalogV2(initialWorkspaceCatalogV2State(), {
72
- version: 2,
73
- daemon: daemon("11111111-1111-4111-8111-111111111111"),
74
- intents: [],
75
- liveSessions: [
76
- { sessionName: "same", fleetSessionId: sameFleetSessionId, paneCount: 1 },
77
- { sessionName: "same", fleetSessionId: sameFleetSessionId, paneCount: 2 },
78
- ],
79
- }),
80
- ).toThrow("duplicate live session");
81
- });
82
-
83
- it("retains the opaque promotion identity on the exact live route", () => {
84
- const state = replaceWorkspaceCatalogV2(initialWorkspaceCatalogV2State(), {
85
- version: 2,
86
- daemon: daemon("11111111-1111-4111-8111-111111111111"),
87
- intents: [],
88
- liveSessions: [{ sessionName: "alpha", fleetSessionId: retiredFleetSessionId, paneCount: 1 }],
89
- });
90
-
91
- expect(state.liveSessions).toEqual([
92
- { sessionName: "alpha", fleetSessionId: retiredFleetSessionId, paneCount: 1 },
93
- ]);
94
- });
95
-
96
- it("rejects one opaque promotion identity assigned to two routing names", () => {
97
- expect(() =>
98
- replaceWorkspaceCatalogV2(initialWorkspaceCatalogV2State(), {
99
- version: 2,
100
- daemon: daemon("11111111-1111-4111-8111-111111111111"),
101
- intents: [],
102
- liveSessions: [
103
- { sessionName: "alpha", fleetSessionId: sameFleetSessionId, paneCount: 1 },
104
- { sessionName: "beta", fleetSessionId: sameFleetSessionId, paneCount: 1 },
105
- ],
106
- }),
107
- ).toThrow("duplicate fleet session");
108
- });
109
- });
@@ -1,59 +0,0 @@
1
- import { describe, expect, it } from "bun:test";
2
- import { readFileSync, readdirSync } from "node:fs";
3
- import { dirname, join } from "node:path";
4
- import { fileURLToPath } from "node:url";
5
-
6
- const packageRoot = join(dirname(fileURLToPath(import.meta.url)), "..");
7
- const workspaceRoot = join(packageRoot, "..", "..");
8
- const productionSources = readdirSync(join(packageRoot, "src"))
9
- .filter((name) => name.endsWith(".ts") && !name.endsWith(".test.ts"))
10
- .map((name) => [name, readFileSync(join(packageRoot, "src", name), "utf8")] as const);
11
-
12
- describe("daemon-client dependency direction", () => {
13
- it("keeps the WorkspaceClient kernel renderer and host neutral", () => {
14
- const forbidden = [
15
- "@opentui/",
16
- "solid-js",
17
- "electron",
18
- "node:fs",
19
- "node:child_process",
20
- "globalThis.WebSocket",
21
- "new WebSocket",
22
- "fetch(",
23
- "packages/daemon/src",
24
- "@tmux-ide/tmux-bridge",
25
- "process.env",
26
- ];
27
- const kernel = productionSources.filter(
28
- ([name]) =>
29
- name.startsWith("workspace-client") ||
30
- name === "terminal-fast-lane.ts" ||
31
- name === "first-latest-coordinator.ts",
32
- );
33
- for (const [name, source] of kernel) {
34
- for (const specifier of forbidden) {
35
- expect(source, `${name} imports or reads ${specifier}`).not.toContain(specifier);
36
- }
37
- }
38
- });
39
-
40
- it("keeps the terminal lane as a composition over the canonical reducer, not a wire protocol", () => {
41
- const lane = readFileSync(join(packageRoot, "src", "terminal-fast-lane.ts"), "utf8");
42
- expect(lane).toContain("applyTerminalReplicaUpdate");
43
- expect(lane).toContain("CanonicalTerminalSubscriptionPort");
44
- expect(lane).not.toContain("TerminalDeliveryEnvelope");
45
- expect(lane).not.toContain("PaneStreamServerFrame");
46
- expect(lane).not.toContain("SchemaZ.parse");
47
- expect(lane).not.toContain("as CanonicalTerminalReplicaUpdate");
48
- });
49
-
50
- it("permits daemon-client -> core while forbidding the reverse edge", () => {
51
- const coreSources = readdirSync(join(workspaceRoot, "packages", "core", "src"))
52
- .filter((name) => name.endsWith(".ts") && !name.endsWith(".test.ts"))
53
- .map((name) => readFileSync(join(workspaceRoot, "packages", "core", "src", name), "utf8"));
54
- expect(productionSources.some(([, source]) => source.includes('from "@tmux-ide/core"'))).toBe(
55
- true,
56
- );
57
- for (const source of coreSources) expect(source).not.toContain("@tmux-ide/daemon-client");
58
- });
59
- });