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,428 +0,0 @@
1
- import { describe, expect, it } from "vitest";
2
- import {
3
- AGENT_GRAPH_LABEL_MAX_LENGTH,
4
- AGENT_GRAPH_MAX_EDGES,
5
- AGENT_GRAPH_MAX_GROUP_MEMBERS,
6
- AGENT_GRAPH_MAX_GROUPS,
7
- AGENT_GRAPH_MAX_NODES,
8
- AgentGraphEdgeKindSchemaZ,
9
- AgentGraphGroupIdSchemaZ,
10
- AgentGraphLabelSchemaZ,
11
- AgentGraphNodeSchemaZ,
12
- AgentGraphOverlaySchemaZ,
13
- isInferredEdgeKind,
14
- projectAgentGraphOverlay,
15
- resolveAgentStatusPresentation,
16
- type AgentGraphDetectStatus,
17
- type AgentGraphEdgeKind,
18
- type AgentGraphNode,
19
- type AgentGraphOverlay,
20
- type AgentGraphProjectionNode,
21
- } from "../agent-graph-overlay.ts";
22
- import { AGENT_ACTIVITY_IDS, CANONICAL_DOMAIN_STATUS_IDS } from "../pane-appearance.ts";
23
-
24
- const NUL = String.fromCharCode(0);
25
- const BELL = String.fromCharCode(7);
26
- const TAB = String.fromCharCode(9);
27
- const ESC = String.fromCharCode(27);
28
- const DEL = String.fromCharCode(127);
29
- const VALID_GROUP_ID = "group.0123456789abcdef";
30
-
31
- function node(windowId: string, overrides: Partial<AgentGraphNode> = {}): AgentGraphNode {
32
- return {
33
- windowId,
34
- status: "working",
35
- statusSource: "authority",
36
- attention: false,
37
- label: windowId,
38
- ...overrides,
39
- };
40
- }
41
-
42
- function overlay(
43
- nodes: AgentGraphNode[],
44
- rest: Partial<AgentGraphOverlay> = {},
45
- ): AgentGraphOverlay {
46
- const record: Record<string, AgentGraphNode> = {};
47
- for (const n of nodes) record[n.windowId] = n;
48
- return { nodes: record, edges: [], groups: [], ...rest } as AgentGraphOverlay;
49
- }
50
-
51
- describe("agent-graph node/group id schemas", () => {
52
- it("keys nodes by durable AppWindow ids and rejects raw pane ids, sessions, and paths", () => {
53
- expect(AgentGraphOverlaySchemaZ.safeParse(overlay([node("terminal.abc")])).success).toBe(true);
54
- expect(AgentGraphOverlaySchemaZ.safeParse(overlay([node("native.home")])).success).toBe(true);
55
-
56
- // A raw tmux pane id starts with `%` — never a valid key.
57
- expect(AgentGraphOverlaySchemaZ.safeParse(overlay([node("%12")])).success).toBe(false);
58
- // A session name with a space is not a durable id.
59
- expect(AgentGraphOverlaySchemaZ.safeParse(overlay([node("my session")])).success).toBe(false);
60
- // An absolute path is not a durable id.
61
- expect(AgentGraphOverlaySchemaZ.safeParse(overlay([node("/tmp/agent")])).success).toBe(false);
62
- });
63
-
64
- it("rejects a reserved value in the node windowId field", () => {
65
- expect(AgentGraphNodeSchemaZ.safeParse(node("__proto__")).success).toBe(false);
66
- expect(AgentGraphNodeSchemaZ.safeParse(node("constructor")).success).toBe(false);
67
- expect(AgentGraphNodeSchemaZ.safeParse(node("terminal.ok")).success).toBe(true);
68
- });
69
-
70
- it("strips a smuggled own __proto__ record key so it never survives as a node", () => {
71
- // JSON.parse creates a real own "__proto__" key — the prototype-pollution vector.
72
- // zod's record parse drops it; the reserved key must never surface as a node.
73
- const payload = JSON.parse(
74
- '{"nodes":{"__proto__":{"windowId":"__proto__","status":"idle",' +
75
- '"statusSource":"unknown","attention":false,"label":null},' +
76
- '"terminal.ok":{"windowId":"terminal.ok","status":"idle",' +
77
- '"statusSource":"unknown","attention":false,"label":null}},"edges":[],"groups":[]}',
78
- ) as unknown;
79
- const parsed = AgentGraphOverlaySchemaZ.safeParse(payload);
80
- expect(parsed.success).toBe(true);
81
- if (parsed.success) {
82
- expect(Object.prototype.hasOwnProperty.call(parsed.data.nodes, "__proto__")).toBe(false);
83
- expect(Object.keys(parsed.data.nodes)).toEqual(["terminal.ok"]);
84
- }
85
- });
86
-
87
- it("accepts prefixed opaque group ids and rejects pane-shaped or reserved values", () => {
88
- expect(AgentGraphGroupIdSchemaZ.safeParse(VALID_GROUP_ID).success).toBe(true);
89
-
90
- expect(AgentGraphGroupIdSchemaZ.safeParse("0123456789abcdef").success).toBe(false); // no prefix
91
- expect(AgentGraphGroupIdSchemaZ.safeParse("group.short").success).toBe(false); // token too short
92
- expect(AgentGraphGroupIdSchemaZ.safeParse("group.%12abcdef012345").success).toBe(false); // pane char
93
- expect(AgentGraphGroupIdSchemaZ.safeParse("group.a/b0123456789abc").success).toBe(false); // path sep
94
- expect(AgentGraphGroupIdSchemaZ.safeParse(`group.${"a".repeat(65)}`).success).toBe(false); // too long
95
- expect(AgentGraphGroupIdSchemaZ.safeParse("__proto__").success).toBe(false); // reserved
96
- });
97
-
98
- it("bounds labels and rejects control characters", () => {
99
- expect(AgentGraphLabelSchemaZ.safeParse("PM · orchestrator").success).toBe(true);
100
- expect(AgentGraphLabelSchemaZ.safeParse("").success).toBe(false);
101
- expect(
102
- AgentGraphLabelSchemaZ.safeParse("a".repeat(AGENT_GRAPH_LABEL_MAX_LENGTH + 1)).success,
103
- ).toBe(false);
104
- for (const bad of [NUL, BELL, TAB, ESC, DEL, "\n", "\r"]) {
105
- expect(AgentGraphLabelSchemaZ.safeParse(`label${bad}x`).success).toBe(false);
106
- }
107
- });
108
- });
109
-
110
- describe("agent-graph edge kinds", () => {
111
- it("carries the two ground-truth and two inferred kinds", () => {
112
- for (const kind of ["spawned", "mission", "inferred-role", "inferred-mission"] as const) {
113
- expect(AgentGraphEdgeKindSchemaZ.safeParse(kind).success).toBe(true);
114
- }
115
- expect(AgentGraphEdgeKindSchemaZ.safeParse("inferred").success).toBe(false);
116
- expect(AgentGraphEdgeKindSchemaZ.safeParse("role").success).toBe(false);
117
- });
118
-
119
- it("classifies only the stamp-derived kinds as inferred", () => {
120
- const kinds: AgentGraphEdgeKind[] = ["spawned", "mission", "inferred-role", "inferred-mission"];
121
- expect(kinds.filter(isInferredEdgeKind)).toEqual(["inferred-role", "inferred-mission"]);
122
- });
123
-
124
- it("accepts an inferred edge between two known nodes", () => {
125
- expect(
126
- AgentGraphOverlaySchemaZ.safeParse(
127
- overlay([node("terminal.lead"), node("terminal.sub")], {
128
- edges: [{ from: "terminal.lead", to: "terminal.sub", kind: "inferred-role" }],
129
- }),
130
- ).success,
131
- ).toBe(true);
132
- });
133
- });
134
-
135
- describe("agent-graph overlay invariants", () => {
136
- it("accepts a coherent overlay with edges and groups", () => {
137
- const parsed = AgentGraphOverlaySchemaZ.safeParse(
138
- overlay([node("terminal.pm"), node("terminal.sub")], {
139
- edges: [{ from: "terminal.pm", to: "terminal.sub", kind: "spawned" }],
140
- groups: [{ id: VALID_GROUP_ID, label: "mission one", memberWindowIds: ["terminal.pm"] }],
141
- }),
142
- );
143
- expect(parsed.success).toBe(true);
144
- });
145
-
146
- it("requires the record key to match the node windowId", () => {
147
- const bad = { nodes: { "terminal.a": node("terminal.b") }, edges: [], groups: [] };
148
- expect(AgentGraphOverlaySchemaZ.safeParse(bad).success).toBe(false);
149
- });
150
-
151
- it("rejects self-edges and edges referencing unknown nodes", () => {
152
- expect(
153
- AgentGraphOverlaySchemaZ.safeParse(
154
- overlay([node("terminal.a")], {
155
- edges: [{ from: "terminal.a", to: "terminal.a", kind: "spawned" }],
156
- }),
157
- ).success,
158
- ).toBe(false);
159
-
160
- expect(
161
- AgentGraphOverlaySchemaZ.safeParse(
162
- overlay([node("terminal.a")], {
163
- edges: [{ from: "terminal.a", to: "terminal.ghost", kind: "mission" }],
164
- }),
165
- ).success,
166
- ).toBe(false);
167
- });
168
-
169
- it("rejects group members that are not nodes, duplicated members, and duplicate group ids", () => {
170
- expect(
171
- AgentGraphOverlaySchemaZ.safeParse(
172
- overlay([node("terminal.a")], {
173
- groups: [{ id: VALID_GROUP_ID, label: "g", memberWindowIds: ["terminal.ghost"] }],
174
- }),
175
- ).success,
176
- ).toBe(false);
177
-
178
- expect(
179
- AgentGraphOverlaySchemaZ.safeParse(
180
- overlay([node("terminal.a")], {
181
- groups: [
182
- { id: VALID_GROUP_ID, label: "g", memberWindowIds: ["terminal.a", "terminal.a"] },
183
- ],
184
- }),
185
- ).success,
186
- ).toBe(false);
187
-
188
- expect(
189
- AgentGraphOverlaySchemaZ.safeParse(
190
- overlay([node("terminal.a")], {
191
- groups: [
192
- { id: VALID_GROUP_ID, label: "one", memberWindowIds: [] },
193
- { id: VALID_GROUP_ID, label: "two", memberWindowIds: [] },
194
- ],
195
- }),
196
- ).success,
197
- ).toBe(false);
198
- });
199
-
200
- it("rejects oversized edge and group payloads", () => {
201
- const tooManyEdges = Array.from({ length: AGENT_GRAPH_MAX_EDGES + 1 }, () => ({
202
- from: "terminal.a",
203
- to: "terminal.b",
204
- kind: "spawned" as const,
205
- }));
206
- expect(
207
- AgentGraphOverlaySchemaZ.safeParse(
208
- overlay([node("terminal.a"), node("terminal.b")], { edges: tooManyEdges }),
209
- ).success,
210
- ).toBe(false);
211
-
212
- const tooManyMembers = Array.from(
213
- { length: AGENT_GRAPH_MAX_GROUP_MEMBERS + 1 },
214
- (_, i) => `terminal.m${i}`,
215
- );
216
- expect(
217
- AgentGraphOverlaySchemaZ.safeParse(
218
- overlay([node("terminal.a")], {
219
- groups: [{ id: VALID_GROUP_ID, label: "g", memberWindowIds: tooManyMembers }],
220
- }),
221
- ).success,
222
- ).toBe(false);
223
- });
224
-
225
- it("rejects unknown record keys on the overlay and its members (strict)", () => {
226
- expect(
227
- AgentGraphOverlaySchemaZ.safeParse({ nodes: {}, edges: [], groups: [], extra: 1 }).success,
228
- ).toBe(false);
229
- });
230
- });
231
-
232
- describe("resolveAgentStatusPresentation", () => {
233
- it("maps every fresh detect status exhaustively", () => {
234
- expect(resolveAgentStatusPresentation({ status: "working", stale: false })).toEqual({
235
- activity: "running",
236
- domainStatus: "running",
237
- attention: false,
238
- });
239
- expect(resolveAgentStatusPresentation({ status: "blocked", stale: false })).toEqual({
240
- activity: "waiting",
241
- domainStatus: "blocked",
242
- attention: true,
243
- });
244
- expect(resolveAgentStatusPresentation({ status: "done", stale: false })).toEqual({
245
- activity: "complete",
246
- domainStatus: "done",
247
- attention: false,
248
- });
249
- expect(resolveAgentStatusPresentation({ status: "idle", stale: false })).toEqual({
250
- activity: "idle",
251
- domainStatus: "idle",
252
- attention: false,
253
- });
254
- expect(resolveAgentStatusPresentation({ status: "unknown", stale: false })).toEqual({
255
- activity: "disconnected",
256
- domainStatus: "disconnected",
257
- attention: false,
258
- });
259
- });
260
-
261
- it("degrades stale working/blocked to recovering, leaving terminal states untouched", () => {
262
- expect(resolveAgentStatusPresentation({ status: "working", stale: true })).toEqual({
263
- activity: "disconnected",
264
- domainStatus: "recovering",
265
- attention: false,
266
- });
267
- expect(resolveAgentStatusPresentation({ status: "blocked", stale: true })).toEqual({
268
- activity: "disconnected",
269
- domainStatus: "recovering",
270
- attention: false,
271
- });
272
- // done/idle are terminal and never go stale.
273
- expect(resolveAgentStatusPresentation({ status: "done", stale: true }).domainStatus).toBe(
274
- "done",
275
- );
276
- expect(resolveAgentStatusPresentation({ status: "idle", stale: true }).domainStatus).toBe(
277
- "idle",
278
- );
279
- });
280
-
281
- it("only ever emits values within the renderer enums", () => {
282
- const activities = new Set<string>(AGENT_ACTIVITY_IDS);
283
- const domains = new Set<string>(CANONICAL_DOMAIN_STATUS_IDS);
284
- const statuses: AgentGraphDetectStatus[] = ["working", "blocked", "done", "idle", "unknown"];
285
- for (const status of statuses) {
286
- for (const stale of [false, true]) {
287
- const out = resolveAgentStatusPresentation({ status, stale });
288
- expect(activities.has(out.activity)).toBe(true);
289
- expect(domains.has(out.domainStatus)).toBe(true);
290
- }
291
- }
292
- });
293
- });
294
-
295
- describe("projectAgentGraphOverlay", () => {
296
- const pnode = (
297
- windowId: string,
298
- over: Partial<AgentGraphProjectionNode> = {},
299
- ): AgentGraphProjectionNode => ({
300
- windowId,
301
- status: "working",
302
- statusSource: "authority",
303
- attention: false,
304
- label: null,
305
- ...over,
306
- });
307
-
308
- it("produces a schema-valid overlay from clean inputs", () => {
309
- const { overlay: result, truncated } = projectAgentGraphOverlay({
310
- nodes: [pnode("terminal.pm"), pnode("terminal.sub", { status: "blocked" })],
311
- edges: [{ from: "terminal.pm", to: "terminal.sub", kind: "spawned" }],
312
- groups: [
313
- { id: VALID_GROUP_ID, label: "m", memberWindowIds: ["terminal.pm", "terminal.sub"] },
314
- ],
315
- });
316
- expect(truncated).toBe(false);
317
- expect(AgentGraphOverlaySchemaZ.safeParse(result).success).toBe(true);
318
- expect(Object.keys(result.nodes)).toHaveLength(2);
319
- });
320
-
321
- it("dedupes nodes (first wins) and flags truncation", () => {
322
- const { overlay: result, truncated } = projectAgentGraphOverlay({
323
- nodes: [pnode("terminal.a", { label: "first" }), pnode("terminal.a", { label: "second" })],
324
- edges: [],
325
- groups: [],
326
- });
327
- expect(truncated).toBe(true);
328
- expect(Object.keys(result.nodes)).toHaveLength(1);
329
- expect(result.nodes["terminal.a"]!.label).toBe("first");
330
- });
331
-
332
- it("drops self-edges, dangling edges, and duplicate edges without throwing", () => {
333
- const { overlay: result, truncated } = projectAgentGraphOverlay({
334
- nodes: [pnode("terminal.a"), pnode("terminal.b")],
335
- edges: [
336
- { from: "terminal.a", to: "terminal.a", kind: "spawned" }, // self
337
- { from: "terminal.a", to: "terminal.ghost", kind: "spawned" }, // dangling
338
- { from: "terminal.a", to: "terminal.b", kind: "mission" },
339
- { from: "terminal.a", to: "terminal.b", kind: "mission" }, // duplicate
340
- ],
341
- groups: [],
342
- });
343
- expect(truncated).toBe(true);
344
- expect(result.edges).toHaveLength(1);
345
- expect(AgentGraphOverlaySchemaZ.safeParse(result).success).toBe(true);
346
- });
347
-
348
- it("keeps inferred edges distinct from ground-truth kinds and dedupes per kind", () => {
349
- const { overlay: result, truncated } = projectAgentGraphOverlay({
350
- nodes: [pnode("terminal.lead"), pnode("terminal.sub")],
351
- edges: [
352
- { from: "terminal.lead", to: "terminal.sub", kind: "spawned" },
353
- { from: "terminal.lead", to: "terminal.sub", kind: "inferred-role" },
354
- { from: "terminal.lead", to: "terminal.sub", kind: "inferred-role" }, // duplicate
355
- { from: "terminal.lead", to: "terminal.sub", kind: "inferred-mission" },
356
- ],
357
- groups: [],
358
- });
359
- // Dedup is per (kind, from, to): the two distinct inferred kinds and the
360
- // spawned edge all survive; only the repeated inferred-role collapses.
361
- expect(truncated).toBe(true);
362
- expect(result.edges.map((edge) => edge.kind).sort()).toEqual([
363
- "inferred-mission",
364
- "inferred-role",
365
- "spawned",
366
- ]);
367
- expect(AgentGraphOverlaySchemaZ.safeParse(result).success).toBe(true);
368
- });
369
-
370
- it("restricts group members to surviving nodes and dedupes group ids", () => {
371
- const { overlay: result, truncated } = projectAgentGraphOverlay({
372
- nodes: [pnode("terminal.a")],
373
- edges: [],
374
- groups: [
375
- {
376
- id: VALID_GROUP_ID,
377
- label: "g",
378
- memberWindowIds: ["terminal.a", "terminal.ghost", "terminal.a"],
379
- },
380
- { id: VALID_GROUP_ID, label: "dup", memberWindowIds: [] },
381
- ],
382
- });
383
- expect(truncated).toBe(true);
384
- expect(result.groups).toHaveLength(1);
385
- expect(result.groups[0]!.memberWindowIds).toEqual(["terminal.a"]);
386
- expect(AgentGraphOverlaySchemaZ.safeParse(result).success).toBe(true);
387
- });
388
-
389
- it("enforces the node cap with honest truncation", () => {
390
- const nodes = Array.from({ length: AGENT_GRAPH_MAX_NODES + 5 }, (_, i) =>
391
- pnode(`terminal.n${i}`),
392
- );
393
- const { overlay: result, truncated } = projectAgentGraphOverlay({
394
- nodes,
395
- edges: [],
396
- groups: [],
397
- });
398
- expect(truncated).toBe(true);
399
- expect(Object.keys(result.nodes)).toHaveLength(AGENT_GRAPH_MAX_NODES);
400
- expect(AgentGraphOverlaySchemaZ.safeParse(result).success).toBe(true);
401
- });
402
-
403
- it("enforces the group cap with honest truncation", () => {
404
- const groups = Array.from({ length: AGENT_GRAPH_MAX_GROUPS + 2 }, (_, i) => ({
405
- id: `group.grp${String(i).padStart(13, "0")}`,
406
- label: `g${i}`,
407
- memberWindowIds: [] as string[],
408
- }));
409
- const { overlay: result, truncated } = projectAgentGraphOverlay({
410
- nodes: [pnode("terminal.a")],
411
- edges: [],
412
- groups,
413
- });
414
- expect(truncated).toBe(true);
415
- expect(result.groups).toHaveLength(AGENT_GRAPH_MAX_GROUPS);
416
- expect(AgentGraphOverlaySchemaZ.safeParse(result).success).toBe(true);
417
- });
418
-
419
- it("returns an empty, valid overlay for empty input", () => {
420
- const { overlay: result, truncated } = projectAgentGraphOverlay({
421
- nodes: [],
422
- edges: [],
423
- groups: [],
424
- });
425
- expect(truncated).toBe(false);
426
- expect(AgentGraphOverlaySchemaZ.safeParse(result).success).toBe(true);
427
- });
428
- });
@@ -1,51 +0,0 @@
1
- import { describe, expect, it } from "vitest";
2
-
3
- import {
4
- AppWindowMutationArgumentsSchemaZ,
5
- AppWindowMutationRequestSchemaZ,
6
- AppWindowMutationResultSchemaZ,
7
- } from "../app-window-mutation.ts";
8
-
9
- const command = { type: "window.move", windowId: "window.shell", x: 10, y: 20 } as const;
10
-
11
- describe("AppWindow mutation contracts", () => {
12
- it("accepts only semantic renderer arguments", () => {
13
- const input = { workspaceName: "alpha", expectedDocumentRevision: 3, command };
14
- expect(AppWindowMutationArgumentsSchemaZ.parse(input)).toEqual(input);
15
- for (const hostile of [
16
- { ...input, operationId: crypto.randomUUID() },
17
- { ...input, expectedDaemonInstanceId: crypto.randomUUID() },
18
- { ...input, projectDir: "/tmp/alpha" },
19
- { ...input, tmuxPaneId: "%4" },
20
- { ...input, command: { ...command, x: Number.POSITIVE_INFINITY } },
21
- { ...input, command: { ...command, x: Number.NaN } },
22
- {
23
- ...input,
24
- command: { type: "window.resize", windowId: "window.shell", width: 0, height: 20 },
25
- },
26
- ]) {
27
- expect(AppWindowMutationArgumentsSchemaZ.safeParse(hostile).success).toBe(false);
28
- }
29
- });
30
-
31
- it("strictly separates host-authored request authority from daemon results", () => {
32
- const request = {
33
- operationId: "00000000-0000-4000-8000-000000000010",
34
- expectedDaemonInstanceId: "00000000-0000-4000-8000-000000000001",
35
- intent: { workspaceName: "alpha", expectedDocumentRevision: 3, command },
36
- };
37
- expect(AppWindowMutationRequestSchemaZ.parse(request)).toEqual(request);
38
- expect(
39
- AppWindowMutationRequestSchemaZ.safeParse({ ...request, bearer: "secret" }).success,
40
- ).toBe(false);
41
- expect(
42
- AppWindowMutationResultSchemaZ.safeParse({
43
- operationId: request.operationId,
44
- daemonInstanceId: request.expectedDaemonInstanceId,
45
- outcome: "applied",
46
- workspaceName: "alpha",
47
- documentRevision: -1,
48
- }).success,
49
- ).toBe(false);
50
- });
51
- });
@@ -1,34 +0,0 @@
1
- import { describe, expect, it } from "vitest";
2
-
3
- import { APP_WINDOW_TIMESTAMP_MAX_LENGTH, AppWindowTimestampSchemaZ } from "../app-window-state.ts";
4
-
5
- describe("app window timestamps", () => {
6
- it("accepts app-generated and reasonable persisted UTC representations", () => {
7
- const values = [
8
- new Date("2026-07-22T10:00:00.123Z").toISOString(),
9
- "2026-07-22T10:00:00Z",
10
- "2026-07-22T10:00:00.1Z",
11
- "2026-07-22T10:00:00.123456Z",
12
- "2026-07-22T10:00:00.123456789Z",
13
- ];
14
-
15
- for (const value of values) {
16
- expect(AppWindowTimestampSchemaZ.parse(value)).toBe(value);
17
- }
18
- expect(values.at(-1)).toHaveLength(APP_WINDOW_TIMESTAMP_MAX_LENGTH);
19
- });
20
-
21
- it("rejects excessive fractional precision and unbounded timestamp text", () => {
22
- expect(AppWindowTimestampSchemaZ.safeParse("2026-07-22T10:00:00.1234567890Z").success).toBe(
23
- false,
24
- );
25
- expect(
26
- AppWindowTimestampSchemaZ.safeParse(`2026-07-22T10:00:00.${"1".repeat(16 * 1024)}Z`).success,
27
- ).toBe(false);
28
- });
29
-
30
- it("retains strict UTC and calendar validation", () => {
31
- expect(AppWindowTimestampSchemaZ.safeParse("2026-07-22T10:00:00+00:00").success).toBe(false);
32
- expect(AppWindowTimestampSchemaZ.safeParse("2026-02-30T10:00:00.000Z").success).toBe(false);
33
- });
34
- });