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
@@ -6,21 +6,26 @@ export interface PerformanceRecordSink {
6
6
  export class BoundedPerformanceRecordWriter {
7
7
  readonly #sink: PerformanceRecordSink;
8
8
  readonly #criticalLimit: number;
9
- readonly #pendingCritical = new Map<string, string>();
9
+ readonly #pendingCritical = new Set<string>();
10
+ readonly #pending: { record: string; bytes: number; key?: string }[] = [];
11
+ readonly #pendingByteLimit: number;
12
+ #pendingBytes = 0;
13
+ #flushPromise: Promise<void> | null = null;
14
+ #resolveFlush: (() => void) | null = null;
10
15
  #saturated = false;
11
16
  #failed = false;
12
17
  #droppedRecords = 0;
13
18
 
14
- constructor(sink: PerformanceRecordSink, criticalLimit = 16) {
19
+ constructor(sink: PerformanceRecordSink, criticalLimit = 16, pendingByteLimit = 64 * 1024) {
15
20
  this.#sink = sink;
16
21
  this.#criticalLimit = criticalLimit;
22
+ this.#pendingByteLimit = pendingByteLimit;
17
23
  }
18
24
 
19
25
  write(record: string): boolean {
20
26
  if (this.#failed) return false;
21
27
  if (this.#saturated) {
22
- this.#droppedRecords += 1;
23
- return false;
28
+ return this.#enqueue(record);
24
29
  }
25
30
  return this.#writeAccepted(record);
26
31
  }
@@ -33,22 +38,57 @@ export class BoundedPerformanceRecordWriter {
33
38
  this.#droppedRecords += 1;
34
39
  return false;
35
40
  }
36
- this.#pendingCritical.set(key, record);
37
- return true;
41
+ return this.#enqueue(record, key);
38
42
  }
39
43
 
40
44
  drain(): void {
41
45
  if (this.#failed) return;
42
46
  this.#saturated = false;
43
- for (const [key, record] of this.#pendingCritical) {
44
- this.#pendingCritical.delete(key);
45
- if (!this.#writeAccepted(record)) break;
47
+ while (this.#pending.length > 0 && !this.#saturated && !this.#failed) {
48
+ const next = this.#pending.shift()!;
49
+ this.#pendingBytes -= next.bytes;
50
+ if (next.key !== undefined) this.#pendingCritical.delete(next.key);
51
+ this.#writeAccepted(next.record);
46
52
  }
53
+ if (this.#pending.length === 0) this.#finishFlush();
54
+ }
55
+
56
+ /** Wait until retained records reach the stream; its owner then flushes/end()s it. */
57
+ flush(): Promise<void> {
58
+ if (this.#failed || this.#pending.length === 0) return Promise.resolve();
59
+ this.#flushPromise ??= new Promise((resolve) => {
60
+ this.#resolveFlush = resolve;
61
+ });
62
+ return this.#flushPromise;
47
63
  }
48
64
 
49
65
  fail(): void {
50
66
  this.#failed = true;
51
67
  this.#pendingCritical.clear();
68
+ this.#pending.length = 0;
69
+ this.#pendingBytes = 0;
70
+ this.#finishFlush();
71
+ }
72
+
73
+ #enqueue(record: string, key?: string): boolean {
74
+ const bytes = Buffer.byteLength(record);
75
+ // Ordinary bursts get one extra stream-sized buffer. Critical records have
76
+ // a separate byte reserve as well as their existing key-count limit.
77
+ const limit = this.#pendingByteLimit + (key === undefined ? 0 : 64 * 1024);
78
+ if (this.#pending.length >= 1024 || this.#pendingBytes + bytes > limit) {
79
+ this.#droppedRecords += 1;
80
+ return false;
81
+ }
82
+ if (key !== undefined) this.#pendingCritical.add(key);
83
+ this.#pending.push({ record, bytes, ...(key === undefined ? {} : { key }) });
84
+ this.#pendingBytes += bytes;
85
+ return true;
86
+ }
87
+
88
+ #finishFlush(): void {
89
+ this.#resolveFlush?.();
90
+ this.#resolveFlush = null;
91
+ this.#flushPromise = null;
52
92
  }
53
93
 
54
94
  diagnostics(): Readonly<{
@@ -400,11 +400,12 @@ export class TerminalFastLaneRendererAdapter implements PaneScopedTerminalAdapte
400
400
  identity.acceptedRevision,
401
401
  ]);
402
402
  if (seen.has(key)) continue;
403
- if (seen.size >= 256) this.#droppedCanonicalHostFrames += 1;
404
- else {
405
- seen.add(key);
406
- identities.push(identity);
407
- }
403
+ // Bound retained de-duplication history, not the renderer's lifetime.
404
+ // An evicted identity may be reported again only after another real paint.
405
+ // Pending identities still have their separate per-frame admission limit.
406
+ if (seen.size >= 256) seen.delete(seen.values().next().value!);
407
+ seen.add(key);
408
+ identities.push(identity);
408
409
  }
409
410
  const dropped = this.#droppedCanonicalHostFrames;
410
411
  this.#droppedCanonicalHostFrames = 0;
@@ -27,6 +27,10 @@ export class TerminalPaneInputRouter<Input> {
27
27
  this.#options = options;
28
28
  }
29
29
 
30
+ get selectionVersion(): number {
31
+ return this.#selectionToken;
32
+ }
33
+
30
34
  get focusedPane(): string | null {
31
35
  return this.#focusedPane;
32
36
  }
@@ -28,6 +28,8 @@ export interface OpenTuiTerminalResourceSampler {
28
28
  dispose(): void;
29
29
  }
30
30
 
31
+ // Limit outstanding low-water sampling chains, not completed observations over
32
+ // the lifetime of a renderer. Each chain owns at most one pending timeout.
31
33
  const TERMINAL_RESOURCE_SAMPLE_LIMIT = 512;
32
34
  // The ProductRig idle proof reads after 10.1s. Emit just before that boundary
33
35
  // so the operation-scoped sample cannot race the proof read.
@@ -315,8 +317,7 @@ function createOpenTuiTerminalResourceSampler(
315
317
  }[];
316
318
  }>,
317
319
  ) => {
318
- if (disposed || resourceEpochIdentity === null || ordinal >= TERMINAL_RESOURCE_SAMPLE_LIMIT)
319
- return;
320
+ if (disposed || resourceEpochIdentity === null) return;
320
321
  ordinal += 1;
321
322
  const now = readDiagnosticNow();
322
323
  if (now === null) return;
@@ -474,7 +475,11 @@ function createOpenTuiTerminalResourceSampler(
474
475
  };
475
476
  return {
476
477
  afterFence(identity) {
477
- if (disposed || ordinal >= TERMINAL_RESOURCE_SAMPLE_LIMIT) return;
478
+ if (disposed) return;
479
+ if (pending.size >= TERMINAL_RESOURCE_SAMPLE_LIMIT) {
480
+ recordSamplingFailure();
481
+ return;
482
+ }
478
483
  latestIdentity = identity;
479
484
  let now: number | null;
480
485
  if (resourceEpochIdentity === null) {
@@ -52,3 +52,35 @@ function graphemes(text: string): string[] {
52
52
  );
53
53
  return [...text];
54
54
  }
55
+
56
+ /** PURE — greedy word-wrap for terminal prose (never returns empty for
57
+ * non-empty text; words longer than the width hard-break). */
58
+ export function wrapText(text: string, width: number): string[] {
59
+ if (width <= 0) return [text];
60
+ const out: string[] = [];
61
+ for (const para of text.split("\n")) {
62
+ let line = "";
63
+ for (const word of para.split(/\s+/).filter(Boolean)) {
64
+ if (line.length === 0) {
65
+ let w = word;
66
+ while (w.length > width) {
67
+ out.push(w.slice(0, width));
68
+ w = w.slice(width);
69
+ }
70
+ line = w;
71
+ } else if (line.length + 1 + word.length <= width) {
72
+ line += ` ${word}`;
73
+ } else {
74
+ out.push(line);
75
+ let w = word;
76
+ while (w.length > width) {
77
+ out.push(w.slice(0, width));
78
+ w = w.slice(width);
79
+ }
80
+ line = w;
81
+ }
82
+ }
83
+ if (line.length > 0 || para.length === 0) out.push(line);
84
+ }
85
+ return out.length > 0 ? out : [""];
86
+ }
@@ -167,9 +167,12 @@ export function createApplicationConnectionFeedback(
167
167
  failure,
168
168
  ...(inventory
169
169
  ? {
170
- recovery: missing
171
- ? "A registered session may have been recreated. Choose that session to restore its identity, then retry here. It may be a different session."
172
- : "Terminal identities conflict or cannot be verified. Copy connection details for diagnosis; Retry does not repair identity conflicts.",
170
+ recovery:
171
+ failure.reason === "duplicate-runtime-pane-binding"
172
+ ? "A terminal is shared by multiple workspace entries. Unlink shared tmux windows so each belongs to one session, then select Retry."
173
+ : missing
174
+ ? "A registered session may have been recreated. Choose that session to restore its identity, then retry here. It may be a different session."
175
+ : "Terminal identities conflict or cannot be verified. Copy connection details for diagnosis; Retry does not repair identity conflicts.",
173
176
  }
174
177
  : {}),
175
178
  };
@@ -5,6 +5,9 @@ export type FleetConnectionFailureCode =
5
5
  | "invalid-target"
6
6
  | "invalid-descriptor"
7
7
  | "incompatible"
8
+ | "ssh-authentication"
9
+ | "ssh-host-key"
10
+ | "remote-cli-missing"
8
11
  | "daemon-missing";
9
12
 
10
13
  export interface FleetConnectionStatus {
@@ -26,7 +29,13 @@ export function fleetConnectionMessage(status: FleetConnectionStatus): string {
26
29
  case "invalid-descriptor":
27
30
  return "Remote daemon discovery returned an invalid response. Check the installation.";
28
31
  case "daemon-missing":
29
- return "No running daemon. Start tmux-ide on this machine, then retry.";
32
+ return "No running daemon. Retrying automatically; start tmux-ide on this machine if needed.";
33
+ case "ssh-authentication":
34
+ return "SSH authentication failed. Check the machine's SSH credentials, then retry.";
35
+ case "ssh-host-key":
36
+ return "SSH host key verification failed. Verify the host in your terminal, then retry.";
37
+ case "remote-cli-missing":
38
+ return "Remote tmux-ide command not found. Check its installation and non-interactive SSH PATH.";
30
39
  case "unavailable":
31
40
  return "Connection failed. Check reachability, SSH authentication and host trust.";
32
41
  default:
@@ -1257,7 +1257,10 @@ export function createWorkspaceClient<
1257
1257
  startApplicationShell();
1258
1258
  if (authorityShell !== null) {
1259
1259
  if (!shellMatchesTerminalAuthority(authorityShell, resource))
1260
- requestTerminalMismatchRefresh(authorityShell, resource);
1260
+ // A newer terminal revision has already established topology. Read
1261
+ // its presentation/refusal details instead of refreshing that same
1262
+ // terminal revision again while leaving the shell stale.
1263
+ shellSession?.refresh();
1261
1264
  }
1262
1265
  return true;
1263
1266
  },
@@ -1,119 +0,0 @@
1
- import { describe, expect, it } from "vitest";
2
- import { ActionContractsZ } from "../actions-contract.ts";
3
-
4
- describe("daemon action contract", () => {
5
- it("supports generation-pinned cooperative shutdown", () => {
6
- const instanceId = "9bcf33b0-c837-4a94-b5e8-c0977f54464f";
7
-
8
- expect(
9
- ActionContractsZ["daemon.shutdown"].input.parse({
10
- reason: "takeover",
11
- expectedInstanceId: instanceId,
12
- }),
13
- ).toEqual({ reason: "takeover", expectedInstanceId: instanceId });
14
- expect(
15
- ActionContractsZ["daemon.shutdown"].input.safeParse({
16
- expectedInstanceId: "not-a-uuid",
17
- }).success,
18
- ).toBe(false);
19
- });
20
-
21
- it("accepts only renderer-safe semantic workspace pane creation", () => {
22
- const input = { kind: "terminal", workspaceName: "workspace.alpha" } as const;
23
- expect(ActionContractsZ["workspace.pane.create"].input.parse(input)).toEqual(input);
24
- for (const [field, value] of [
25
- ["cwd", "/tmp/project"],
26
- ["argv", ["sh", "-c", "owned"]],
27
- ["env", { SECRET: "renderer" }],
28
- ["paneId", "%42"],
29
- ["sessionName", "runtime-session"],
30
- ] as const) {
31
- expect(
32
- ActionContractsZ["workspace.pane.create"].input.safeParse({
33
- ...input,
34
- [field]: value,
35
- }).success,
36
- ).toBe(false);
37
- }
38
- });
39
-
40
- it("renames panes through semantic identity only", () => {
41
- const input = {
42
- workspaceName: "workspace.alpha",
43
- scope: "pane",
44
- semanticPaneId: "pane.main",
45
- name: "Build monitor",
46
- } as const;
47
- expect(ActionContractsZ["workspace.rename"].input.parse(input)).toEqual(input);
48
- expect(
49
- ActionContractsZ["workspace.rename"].input.safeParse({
50
- ...input,
51
- semanticPaneId: "%42",
52
- }).success,
53
- ).toBe(false);
54
- });
55
-
56
- it("keeps config-free workspace admission semantic and its result browser-safe", () => {
57
- expect(ActionContractsZ["workspace.open"].input.parse({ projectDir: "/tmp/project" })).toEqual({
58
- projectDir: "/tmp/project",
59
- });
60
- for (const [field, value] of [
61
- ["sessionName", "renderer-session"],
62
- ["paneId", "%42"],
63
- ["command", ["sh", "-c", "owned"]],
64
- ["env", { SECRET: "renderer" }],
65
- ] as const) {
66
- expect(
67
- ActionContractsZ["workspace.open"].input.safeParse({
68
- projectDir: "/tmp/project",
69
- [field]: value,
70
- }).success,
71
- ).toBe(false);
72
- }
73
-
74
- const result = ActionContractsZ["workspace.open"].result.parse({
75
- operationId: "10000000-0000-4000-8000-000000000001",
76
- daemonInstanceId: "20000000-0000-4000-8000-000000000002",
77
- outcome: "created",
78
- resource: {
79
- resourceVersion: 1,
80
- workspaceName: "project-00112233445566778899aabbccddeeff",
81
- initialPaneId: "pane.workspace.00112233445566778899aabbccddeeff",
82
- },
83
- });
84
- expect(JSON.stringify(result)).not.toMatch(/projectDir|sessionName|runtime|tmux|path/u);
85
- });
86
-
87
- it("lets the trusted desktop host select a folder without exposing its path", () => {
88
- const input = {
89
- source: { kind: "host-selection" },
90
- previousWorkspaceName: "workspace.alpha",
91
- } as const;
92
- expect(ActionContractsZ["workspace.open.prepare"].input.parse(input)).toEqual(input);
93
- expect(
94
- ActionContractsZ["workspace.open.prepare"].input.safeParse({
95
- ...input,
96
- source: { kind: "host-selection", projectDir: "/private/project" },
97
- }).success,
98
- ).toBe(false);
99
- });
100
-
101
- it("accepts only semantic pane identities for a swap", () => {
102
- const input = {
103
- workspaceName: "workspace.alpha",
104
- sourceSemanticPaneId: "pane.source",
105
- targetSemanticPaneId: "pane.target",
106
- } as const;
107
- expect(ActionContractsZ["workspace.pane.swap"].input.parse(input)).toEqual(input);
108
- for (const unsafe of [
109
- { sourcePaneId: "%1" },
110
- { targetPaneId: "%2" },
111
- { tmuxCommand: "swap-pane -D" },
112
- { sessionName: "runtime-session" },
113
- ]) {
114
- expect(
115
- ActionContractsZ["workspace.pane.swap"].input.safeParse({ ...input, ...unsafe }).success,
116
- ).toBe(false);
117
- }
118
- });
119
- });