instar 1.3.1592 → 1.3.1593

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 (72) hide show
  1. package/dashboard/desktop.css +1 -0
  2. package/dashboard/desktop.html +7 -0
  3. package/dashboard/desktop.js +205 -6
  4. package/dist/core/AutonomousStartAdmission.d.ts +10 -4
  5. package/dist/core/AutonomousStartAdmission.d.ts.map +1 -1
  6. package/dist/core/AutonomousStartAdmission.js +14 -9
  7. package/dist/core/AutonomousStartAdmission.js.map +1 -1
  8. package/dist/core/DesktopHost.d.ts +30 -0
  9. package/dist/core/DesktopHost.d.ts.map +1 -1
  10. package/dist/core/DesktopHost.js +24 -0
  11. package/dist/core/DesktopHost.js.map +1 -1
  12. package/dist/core/DirectDesktopAccess.d.ts +11 -1
  13. package/dist/core/DirectDesktopAccess.d.ts.map +1 -1
  14. package/dist/core/DirectDesktopAccess.js +46 -0
  15. package/dist/core/DirectDesktopAccess.js.map +1 -1
  16. package/dist/core/MacDesktopHost.d.ts +12 -1
  17. package/dist/core/MacDesktopHost.d.ts.map +1 -1
  18. package/dist/core/MacDesktopHost.js +70 -6
  19. package/dist/core/MacDesktopHost.js.map +1 -1
  20. package/dist/core/PostUpdateMigrator.d.ts.map +1 -1
  21. package/dist/core/PostUpdateMigrator.js +12 -1
  22. package/dist/core/PostUpdateMigrator.js.map +1 -1
  23. package/dist/core/WindowRunCadenceExecutor.d.ts +24 -4
  24. package/dist/core/WindowRunCadenceExecutor.d.ts.map +1 -1
  25. package/dist/core/WindowRunCadenceExecutor.js +138 -18
  26. package/dist/core/WindowRunCadenceExecutor.js.map +1 -1
  27. package/dist/core/WindowRunLivenessAuthority.d.ts +48 -4
  28. package/dist/core/WindowRunLivenessAuthority.d.ts.map +1 -1
  29. package/dist/core/WindowRunLivenessAuthority.js +186 -30
  30. package/dist/core/WindowRunLivenessAuthority.js.map +1 -1
  31. package/dist/core/WindowsDesktopHost.d.ts +9 -1
  32. package/dist/core/WindowsDesktopHost.d.ts.map +1 -1
  33. package/dist/core/WindowsDesktopHost.js +43 -4
  34. package/dist/core/WindowsDesktopHost.js.map +1 -1
  35. package/dist/core/WindowsDesktopLocalTransport.js +1 -1
  36. package/dist/core/WindowsDesktopLocalTransport.js.map +1 -1
  37. package/dist/data/standards-guard-index.json +1 -1
  38. package/dist/data/standards-guard-index.meta.json +2 -2
  39. package/dist/data/standards-registry.meta.json +1 -1
  40. package/dist/native/instar-desktop-host +0 -0
  41. package/dist/native/windows/InstarDesktopCompanion.cs +84 -16
  42. package/dist/scaffold/templates.d.ts.map +1 -1
  43. package/dist/scaffold/templates.js +1 -1
  44. package/dist/scaffold/templates.js.map +1 -1
  45. package/dist/server/AgentServer.d.ts.map +1 -1
  46. package/dist/server/AgentServer.js +6 -7
  47. package/dist/server/AgentServer.js.map +1 -1
  48. package/dist/server/CapabilityIndex.js +1 -1
  49. package/dist/server/CapabilityIndex.js.map +1 -1
  50. package/dist/server/DesktopMeshBroker.d.ts +1 -1
  51. package/dist/server/DesktopMeshBroker.d.ts.map +1 -1
  52. package/dist/server/DesktopMeshBroker.js.map +1 -1
  53. package/dist/server/DesktopStreamManager.d.ts +16 -0
  54. package/dist/server/DesktopStreamManager.d.ts.map +1 -1
  55. package/dist/server/DesktopStreamManager.js +39 -1
  56. package/dist/server/DesktopStreamManager.js.map +1 -1
  57. package/dist/server/routes.d.ts.map +1 -1
  58. package/dist/server/routes.js +85 -23
  59. package/dist/server/routes.js.map +1 -1
  60. package/package.json +1 -1
  61. package/scripts/windows-desktop-local-transport.ps1 +2 -2
  62. package/src/data/builtin-manifest.json +64 -64
  63. package/src/data/standards-guard-index.json +1 -1
  64. package/src/data/standards-guard-index.meta.json +2 -2
  65. package/src/data/standards-registry.meta.json +1 -1
  66. package/src/scaffold/templates.ts +1 -1
  67. package/upgrades/1.3.1593.md +53 -0
  68. package/upgrades/side-effects/desktop-multi-display-gestures.md +73 -0
  69. package/upgrades/side-effects/desktop-stream-frame-stats.md +45 -0
  70. package/upgrades/side-effects/window-run-liveness-per-topic.eli16.md +28 -0
  71. package/upgrades/side-effects/window-run-liveness-per-topic.md +81 -0
  72. package/upgrades/1.3.1592.md +0 -22
@@ -20,6 +20,7 @@ body.desktop-live #keyboardBar input{-webkit-touch-callout:default;-webkit-user-
20
20
  .desktop-dock button{min-width:2.9rem;min-height:2.9rem;padding:.35rem;background:#111827e8;color:#f8fafc;border:1px solid #64748b;box-shadow:0 2px 12px #0009}
21
21
  .desktop-tools{position:absolute;z-index:6;right:4rem;bottom:max(.7rem,env(safe-area-inset-bottom));width:min(19rem,calc(100vw - 5rem));max-height:min(60dvh,32rem);overflow:auto;display:flex;flex-wrap:wrap;gap:.4rem;padding:.55rem;background:#111827f2;border:1px solid #64748b;border-radius:10px;box-shadow:0 4px 18px #0009}
22
22
  .desktop-tools[hidden],#keyboardBar[hidden],.desktop-dock button[hidden],.desktop-tools button[hidden]{display:none}
23
+ .display-note{flex:1 0 100%;margin:0;font-size:.8rem;color:#f8fafc}.display-note[hidden]{display:none}#displayMenu button{flex:1 0 100%;text-align:left}
23
24
  .desktop-tools button{flex:1 0 auto;padding:.5rem .65rem}.type-label{display:block;margin:0;font-size:.8rem}
24
25
  .desktop-tools button[aria-pressed="true"]{background:#fbbf24;color:#422006}
25
26
  #keyboardBar{position:absolute;z-index:7;left:max(.5rem,env(safe-area-inset-left));right:max(.5rem,env(safe-area-inset-right));bottom:max(.5rem,env(safe-area-inset-bottom));display:flex;align-items:center;gap:.4rem;padding:.4rem;background:#111827f2;border:1px solid #64748b;border-radius:10px}
@@ -36,11 +36,18 @@
36
36
  </div>
37
37
  <div class="desktop-dock" aria-label="Remote desktop controls">
38
38
  <button id="toolsButton" type="button" aria-label="More controls" aria-expanded="false" aria-controls="desktopTools">☰</button>
39
+ <button id="displaysButton" type="button" aria-label="Screens" aria-expanded="false" aria-controls="displayMenu" hidden>⧉</button>
39
40
  <button id="keyboardButton" type="button" aria-label="Show keyboard" aria-expanded="false" aria-controls="keyboardBar">⌨</button>
40
41
  <button id="zoomResetButton" type="button" aria-label="Fit screen" hidden>Fit</button>
41
42
  <button id="fullscreenButton" type="button" aria-label="Full screen">⛶</button>
42
43
  </div>
44
+ <div class="desktop-tools" id="displayMenu" aria-label="Screens" hidden></div>
43
45
  <div class="desktop-tools" id="desktopTools" hidden>
46
+ <p id="displayNote" class="display-note" hidden></p>
47
+ <button data-shortcut="overview" type="button" hidden></button>
48
+ <button data-shortcut="appWindows" type="button" hidden></button>
49
+ <button data-shortcut="previousSpace" type="button" hidden></button>
50
+ <button data-shortcut="nextSpace" type="button" hidden></button>
44
51
  <button id="modeButton" type="button" aria-pressed="true" hidden>Trackpad · swipe to move</button>
45
52
  <button id="dragButton" type="button" aria-pressed="false">Drag</button>
46
53
  <button id="rightButton" type="button">Right click</button>
@@ -89,8 +89,38 @@ const LONG_PRESS_MS = 550;
89
89
  const DOUBLE_TAP_MS = 300;
90
90
  let mousePress = null;
91
91
  let lastTap = null;
92
+ // A lone tap's click waits this long. A click followed at once by a press reads on
93
+ // the host as a double-click, which maximizes a window being dragged by its title.
94
+ let pendingTapClick = 0;
92
95
  let dragPointerId = null;
93
96
  let multiTap = null;
97
+ // What the connected machine says about its screens. Until it answers
98
+ // supported, selectDisplay is never sent: an older host ends the session on a
99
+ // command it does not know.
100
+ let displayInfo = null;
101
+ let overviewOpen = null;
102
+ let threeFinger = null;
103
+ const THREE_FINGER_TRAVEL = 60;
104
+ // While a switch settles the picture still shows the old screen, and a tap would
105
+ // land on the new one at the wrong place. Hold pointer presses until a new frame.
106
+ let screenSwitch = null;
107
+ const SCREEN_SWITCH_SETTLE_MS = 400;
108
+ const SCREEN_SWITCH_LIMIT_MS = 3_000;
109
+ // Standard shortcuts, sent as ordinary keys. Spaces follow the fingers as on a
110
+ // Mac trackpad: swiping left brings in the Space on the right.
111
+ const DESKTOP_SHORTCUTS = {
112
+ macos: {
113
+ overview: { label: 'Mission Control', hint: 'Control+Up', modifiers: ['Control'], key: 'ArrowUp' },
114
+ appWindows: { label: 'App windows', hint: 'Control+Down', modifiers: ['Control'], key: 'ArrowDown' },
115
+ nextSpace: { label: 'Next Space', hint: 'Control+Right', modifiers: ['Control'], key: 'ArrowRight' },
116
+ previousSpace: { label: 'Previous Space', hint: 'Control+Left', modifiers: ['Control'], key: 'ArrowLeft' },
117
+ },
118
+ windows: {
119
+ overview: { label: 'Task View', hint: 'Win+Tab', modifiers: ['Meta'], key: 'Tab' },
120
+ nextSpace: { label: 'Next desktop', hint: 'Ctrl+Win+Right', modifiers: ['Control', 'Meta'], key: 'ArrowRight' },
121
+ previousSpace: { label: 'Previous desktop', hint: 'Ctrl+Win+Left', modifiers: ['Control', 'Meta'], key: 'ArrowLeft' },
122
+ },
123
+ };
94
124
 
95
125
  // Watching counts as using the session: while the viewer is visible a light
96
126
  // ping keeps the two-minute idle limit from ending it.
@@ -134,6 +164,7 @@ function releaseButton() {
134
164
  }
135
165
  function beginHold(button) {
136
166
  if (heldButton) return;
167
+ overviewOpen = null; // This press may close it.
137
168
  flushPendingMove();
138
169
  buttonReleaseRequested = false;
139
170
  const epoch = streamEpoch;
@@ -393,6 +424,7 @@ async function receiveFrame(recordBuffer, epoch) {
393
424
  additionalData: recordAad('frame') }, aesKey, record.subarray(8));
394
425
  if (!inputEnabled || epoch !== streamEpoch) return;
395
426
  frameSequence = sequence;
427
+ if (screenSwitch && Date.now() - screenSwitch.at >= SCREEN_SWITCH_SETTLE_MS) screenSwitch = null;
396
428
  const bytes = new Uint8Array(frame);
397
429
  if (bytes[0] !== 0xff || bytes[1] !== 0xd8) {
398
430
  try { receiveH264(bytes, epoch); }
@@ -428,6 +460,11 @@ function leave(message) {
428
460
  pendingWheel = null;
429
461
  stopEdgePan();
430
462
  pointers.clear();
463
+ displayInfo = null;
464
+ overviewOpen = null;
465
+ threeFinger = null;
466
+ screenSwitch = null;
467
+ renderDisplays();
431
468
  setHeldButton(null);
432
469
  for (const key of heldKeys.keys()) { heldKeys.delete(key); keyOperationIds.delete(key); updateKeyButton(key); }
433
470
  keyReleaseRequested.clear();
@@ -868,10 +905,12 @@ async function openStream(result, resume = null) {
868
905
  updateCursor();
869
906
  $('machineName').textContent = ticket.label;
870
907
  status('Remote desktop is live.');
908
+ void refreshDisplays(epoch);
871
909
  if (resume !== null) resumeAttempt = null;
872
910
  resumeTransportFailures = 0;
873
911
  heartbeat = setInterval(() => {
874
912
  sendCommand({ type: 'ping' });
913
+ void refreshDisplays(epoch); // Picks up a screen plugged in, unplugged, or a read that failed.
875
914
  }, 30_000);
876
915
  resolve();
877
916
  });
@@ -893,6 +932,8 @@ async function openStream(result, resume = null) {
893
932
 
894
933
  function send(action) {
895
934
  if (!inputEnabled) return Promise.resolve(false);
935
+ if (screenSwitch && Date.now() - screenSwitch.at >= SCREEN_SWITCH_LIMIT_MS) screenSwitch = null;
936
+ if (screenSwitch && ['click', 'buttonDown', 'move'].includes(action.kind)) return Promise.resolve(false);
896
937
  return sendCommand({ type: 'input', action });
897
938
  }
898
939
  function imageArea() {
@@ -981,9 +1022,127 @@ function edgePanTick() {
981
1022
  }
982
1023
  }
983
1024
  function clickCursor(button = 'left', count = 1) {
1025
+ overviewOpen = null; // A click may have closed it.
984
1026
  if (!heldButton) send(count > 1 ? { kind: 'click', ...cursor, button, count } : { kind: 'click', ...cursor, button });
985
1027
  }
986
1028
  function heldModifiers() { return modifierKeys.filter(key => heldKeys.has(key)); }
1029
+ /** Resolves to the new list, or null when this read told us nothing new. */
1030
+ async function refreshDisplays(epoch = streamEpoch) {
1031
+ let info;
1032
+ try { info = await api(`/desktop/requests/${encodeURIComponent(requestId)}/displays`); }
1033
+ catch { info = { supported: false, platform: null, displays: [], currentDisplayId: null, canShowAll: false }; }
1034
+ if (epoch !== streamEpoch) return null;
1035
+ // One failed read must not take working controls away; the next one retries.
1036
+ if (displayInfo?.supported && !info.supported) return null;
1037
+ displayInfo = info;
1038
+ renderDisplays();
1039
+ return info;
1040
+ }
1041
+ function displayChoices() {
1042
+ const info = displayInfo;
1043
+ if (!info?.supported) return [];
1044
+ const rows = info.displays.map(display => ({ id: display.id,
1045
+ label: `${display.name} · ${display.width}×${display.height}${display.main ? ' · Main' : ''}` }));
1046
+ return info.canShowAll ? [{ id: null, label: 'All screens' }, ...rows] : rows;
1047
+ }
1048
+ function renderDisplays() {
1049
+ const menu = $('displayMenu');
1050
+ const button = $('displaysButton');
1051
+ if (!menu || !button) return;
1052
+ const info = displayInfo;
1053
+ const choices = displayChoices();
1054
+ button.hidden = !info?.supported || info.displays.length < 2;
1055
+ if (button.hidden) { menu.hidden = true; button.setAttribute('aria-expanded', 'false'); }
1056
+ menu.replaceChildren(...choices.map(choice => {
1057
+ const item = document.createElement('button');
1058
+ item.type = 'button';
1059
+ item.textContent = choice.label; // Host text: never markup.
1060
+ item.setAttribute('aria-pressed', String(choice.id === info.currentDisplayId));
1061
+ item.addEventListener('click', () => { void chooseDisplay(choice.id); });
1062
+ return item;
1063
+ }));
1064
+ const shortcuts = DESKTOP_SHORTCUTS[info?.platform] ?? null;
1065
+ for (const node of document.querySelectorAll('[data-shortcut]')) {
1066
+ const action = shortcuts?.[node.dataset.shortcut];
1067
+ node.hidden = !action;
1068
+ if (action) node.textContent = action.label;
1069
+ }
1070
+ const note = $('displayNote');
1071
+ if (note) {
1072
+ note.hidden = !info || info.supported;
1073
+ if (!note.hidden) note.textContent = 'This machine needs an update before you can switch screens.';
1074
+ }
1075
+ }
1076
+ async function chooseDisplay(displayId) {
1077
+ if (!displayInfo?.supported || !inputEnabled) return;
1078
+ const epoch = streamEpoch;
1079
+ const chosen = displayChoices().find(choice => choice.id === displayId);
1080
+ $('displayMenu').hidden = true;
1081
+ $('displaysButton').setAttribute('aria-expanded', 'false');
1082
+ overviewOpen = null;
1083
+ flushPendingMove();
1084
+ resetZoom();
1085
+ releaseButton();
1086
+ if (!await send({ kind: 'selectDisplay', displayId })) return;
1087
+ // macOS applies Spaces to the screen under the pointer, so the gestures
1088
+ // follow the picture only if the pointer does.
1089
+ cursor = { x: 0.5, y: 0.5 };
1090
+ void send({ kind: 'move', ...cursor });
1091
+ screenSwitch = { at: Date.now() };
1092
+ updateCursor();
1093
+ status(`Showing ${chosen?.label.split(' · ')[0] ?? 'the chosen screen'}.`);
1094
+ await new Promise(resolve => setTimeout(resolve, 1_200));
1095
+ const info = await refreshDisplays(epoch);
1096
+ if (info?.supported && info.currentDisplayId !== displayId) {
1097
+ status('That screen is not available any more.');
1098
+ }
1099
+ }
1100
+ async function sendChord(modifiers, key) {
1101
+ const epoch = streamEpoch;
1102
+ const pressed = [];
1103
+ let allDown = true;
1104
+ for (const modifier of modifiers) {
1105
+ if (heldKeys.has(modifier)) continue; // A key the operator latched stays latched.
1106
+ if (!await beginKey(modifier)) { allDown = false; break; }
1107
+ pressed.push(modifier);
1108
+ }
1109
+ if (allDown && epoch === streamEpoch) await tapKey(key);
1110
+ for (const modifier of pressed.reverse()) if (epoch === streamEpoch) await releaseKey(modifier);
1111
+ }
1112
+ function runShortcut(name) {
1113
+ const shortcuts = DESKTOP_SHORTCUTS[displayInfo?.platform];
1114
+ const action = shortcuts?.[name];
1115
+ if (!action || !inputEnabled) return;
1116
+ // Named beside the action: this Mac may have the shortcut turned off, and
1117
+ // the viewer cannot see that.
1118
+ status(`${action.label} (${action.hint})`);
1119
+ overviewOpen = name === 'overview' || name === 'appWindows' ? name : null;
1120
+ void sendChord(action.modifiers, action.key);
1121
+ }
1122
+ function closeOverview() {
1123
+ overviewOpen = null;
1124
+ status('Back');
1125
+ void tapKey('Escape');
1126
+ }
1127
+ function swipeThreeFingers(direction) {
1128
+ if (direction === 'left') runShortcut('nextSpace');
1129
+ else if (direction === 'right') runShortcut('previousSpace');
1130
+ else if (direction === 'up') {
1131
+ if (overviewOpen === 'appWindows') closeOverview();
1132
+ else if (!overviewOpen) runShortcut('overview');
1133
+ } else if (overviewOpen) closeOverview();
1134
+ else runShortcut('appWindows');
1135
+ }
1136
+ function moveThreeFingers() {
1137
+ if (!threeFinger || threeFinger.fired || pointers.size < 3 || heldButton) return;
1138
+ const fingers = [...pointers.values()];
1139
+ const dx = fingers.reduce((sum, state) => sum + state.x - state.startX, 0) / fingers.length;
1140
+ const dy = fingers.reduce((sum, state) => sum + state.y - state.startY, 0) / fingers.length;
1141
+ const major = Math.max(Math.abs(dx), Math.abs(dy));
1142
+ if (major < THREE_FINGER_TRAVEL || major < 1.5 * Math.min(Math.abs(dx), Math.abs(dy))) return;
1143
+ threeFinger.fired = true; // One swipe, one action.
1144
+ swipeThreeFingers(Math.abs(dx) > Math.abs(dy) ? (dx < 0 ? 'left' : 'right') : (dy < 0 ? 'up' : 'down'));
1145
+ }
987
1146
  function syncTouchModeButton() {
988
1147
  $('modeButton').hidden = !touchCapable;
989
1148
  $('modeButton').textContent = trackpad ? 'Trackpad · swipe to move' : 'Direct · touch position';
@@ -1076,6 +1235,18 @@ $('keyboardButton').addEventListener('click', () => {
1076
1235
  syncVisualViewport();
1077
1236
  });
1078
1237
  $('hideKeyboardButton').addEventListener('click', closeKeyboard);
1238
+ $('displaysButton')?.addEventListener('click', () => {
1239
+ const open = $('displayMenu').hidden;
1240
+ $('displayMenu').hidden = !open;
1241
+ $('displaysButton').setAttribute('aria-expanded', String(open));
1242
+ if (open) void refreshDisplays(); // A screen may have been plugged in since.
1243
+ });
1244
+ for (const button of document.querySelectorAll('[data-shortcut]')) {
1245
+ button.addEventListener('click', () => {
1246
+ if (overviewOpen && button.dataset.shortcut === overviewOpen) closeOverview();
1247
+ else runShortcut(button.dataset.shortcut);
1248
+ });
1249
+ }
1079
1250
  $('zoomResetButton').addEventListener('click', resetZoom);
1080
1251
  $('fullscreenButton').hidden = !document.fullscreenEnabled || !$('control').requestFullscreen;
1081
1252
  $('fullscreenButton').addEventListener('click', () => {
@@ -1159,8 +1330,10 @@ $('surface').addEventListener('pointerdown', event => {
1159
1330
  multiTap = null;
1160
1331
  const state = pointers.get(event.pointerId);
1161
1332
  const now = Date.now();
1162
- state.secondTap = !!lastTap && now - lastTap.at < DOUBLE_TAP_MS
1333
+ state.secondTap = !!pendingTapClick && !!lastTap && now - lastTap.at < DOUBLE_TAP_MS
1163
1334
  && Math.hypot(event.clientX - lastTap.x, event.clientY - lastTap.y) < 40;
1335
+ if (state.secondTap) { clearTimeout(pendingTapClick); pendingTapClick = 0; }
1336
+ else flushTapClick();
1164
1337
  // Hold still to right-click, as on AnyDesk and most phone remote desktops.
1165
1338
  state.longPress = setTimeout(() => {
1166
1339
  if (pointers.get(event.pointerId) !== state || state.maxDistance >= 10 || state.multi || state.secondTap) return;
@@ -1175,6 +1348,12 @@ $('surface').addEventListener('pointerdown', event => {
1175
1348
  const pair = pairMetrics();
1176
1349
  twoFinger = { ...pair, zoom, panX, panY, lastX: pair.x, lastY: pair.y, mode: 'pending' };
1177
1350
  }
1351
+ if (pointers.size === 3 && event.pointerType !== 'mouse') {
1352
+ stopEdgePan();
1353
+ twoFinger = null;
1354
+ for (const state of pointers.values()) { state.startX = state.x; state.startY = state.y; }
1355
+ threeFinger = { fired: false };
1356
+ }
1178
1357
  if (!trackpad || event.pointerType === 'mouse') {
1179
1358
  const at = position(event);
1180
1359
  if (at) { cursor = at; updateCursor(); queueMove(at); }
@@ -1211,7 +1390,9 @@ $('surface').addEventListener('pointermove', event => {
1211
1390
  state.x = event.clientX; state.y = event.clientY;
1212
1391
  state.maxDistance = Math.max(state.maxDistance,
1213
1392
  Math.hypot(event.clientX - state.startX, event.clientY - state.startY));
1214
- if (pointers.size > 1 && event.pointerType !== 'mouse') {
1393
+ if (threeFinger && event.pointerType !== 'mouse') {
1394
+ moveThreeFingers();
1395
+ } else if (pointers.size > 1 && event.pointerType !== 'mouse') {
1215
1396
  moveTwoFingers();
1216
1397
  } else if (state.multi && event.pointerType !== 'mouse') {
1217
1398
  // Do not turn the trailing finger of a scroll gesture into pointer motion.
@@ -1233,6 +1414,7 @@ $('surface').addEventListener('pointerup', event => {
1233
1414
  clearTimeout(state.longPress);
1234
1415
  pointers.delete(event.pointerId);
1235
1416
  if (pointers.size < 2) twoFinger = null;
1417
+ if (pointers.size === 0) threeFinger = null;
1236
1418
  if (event.pointerType === 'mouse' && mousePress?.pointerId === event.pointerId) {
1237
1419
  const press = mousePress; mousePress = null;
1238
1420
  const at = position(event);
@@ -1268,17 +1450,34 @@ $('surface').addEventListener('pointerup', event => {
1268
1450
  }
1269
1451
  const distance = Math.max(state.maxDistance,
1270
1452
  Math.hypot(event.clientX - state.startX, event.clientY - state.startY));
1271
- if (!state.multi && distance < 10 && Date.now() - state.at < 500) {
1453
+ if (!state.multi && distance < 10 && state.secondTap) {
1454
+ // The first tap's click is still unsent: a real double tap goes out as one
1455
+ // double-click, and a second press held without moving as one click.
1456
+ if (!trackpad) { const at = position(event); if (at) cursor = at; }
1457
+ flushPendingMove();
1458
+ clickCursor('left', Date.now() - state.at < 500 ? 2 : 1);
1459
+ lastTap = null;
1460
+ } else if (!state.multi && distance < 10 && Date.now() - state.at < 500) {
1272
1461
  if (!trackpad || event.pointerType === 'mouse') { const at = position(event); if (at) cursor = at; }
1273
- clickCursor(event.button === 2 ? 'right' : 'left');
1274
- lastTap = event.pointerType === 'mouse' ? null : { at: Date.now(), x: event.clientX, y: event.clientY };
1462
+ if (event.pointerType === 'mouse') { clickCursor(event.button === 2 ? 'right' : 'left'); lastTap = null; }
1463
+ else {
1464
+ lastTap = { at: Date.now(), x: event.clientX, y: event.clientY };
1465
+ pendingTapClick = setTimeout(flushTapClick, DOUBLE_TAP_MS);
1466
+ }
1275
1467
  }
1276
1468
  });
1277
1469
  function twoFingerUsed(tap) { return tap.zoomed === true; }
1470
+ function flushTapClick() {
1471
+ if (!pendingTapClick) return;
1472
+ clearTimeout(pendingTapClick);
1473
+ pendingTapClick = 0;
1474
+ clickCursor('left');
1475
+ }
1278
1476
  function cancelGestures() {
1279
1477
  stopEdgePan();
1478
+ clearTimeout(pendingTapClick); pendingTapClick = 0;
1280
1479
  for (const state of pointers.values()) clearTimeout(state.longPress);
1281
- pointers.clear(); twoFinger = null; multiTap = null; mousePress = null; dragPointerId = null; lastTap = null;
1480
+ pointers.clear(); twoFinger = null; threeFinger = null; multiTap = null; mousePress = null; dragPointerId = null; lastTap = null;
1282
1481
  releaseControls();
1283
1482
  }
1284
1483
  $('surface').addEventListener('pointercancel', cancelGestures);
@@ -12,14 +12,18 @@
12
12
  *
13
13
  * THE FIX:
14
14
  * 1. `decideAutonomousStartStatus` — 'preparing' only while a W32 window
15
- * lifecycle is genuinely open AND its single liveness slot can take this
16
- * run. Every other run starts 'active', so the reconciler revives it if its
15
+ * lifecycle is genuinely open AND this topic's liveness binding can take
16
+ * this run. Every other run starts 'active', so the reconciler revives it if its
17
17
  * session dies.
18
18
  * 2. `PreparingRunWatchdog` — any open run still 'preparing' past a few
19
19
  * minutes gets ONE plain notice in its own topic. A run that cannot start
20
20
  * is never silent. At most PREPARING_NOTICE_MAX_ATTEMPTS sends per run,
21
21
  * counted on the durable run record, so a dead delivery path cannot loop.
22
22
  *
23
+ * Liveness holds one binding PER TOPIC (2026-11-01, topic 10000001256): it
24
+ * used to hold one binding for the whole agent, so a run in one topic left a
25
+ * run in another 'preparing' with nothing able to promote it.
26
+ *
23
27
  * @self-action-controller: preparing-run-watchdog
24
28
  */
25
29
  import type { AutonomousRunRecord, AutonomousRunStore } from './AutonomousRunStore.js';
@@ -34,7 +38,7 @@ export declare function telegramTopicNotifier(send: (topic: number, text: string
34
38
  export interface StartAdmissionInput {
35
39
  projectName: string;
36
40
  topicId: string;
37
- /** WindowRunLivenessAuthority.status(), or null/undefined when the authority is dark. */
41
+ /** WindowRunLivenessAuthority.status(topicId) for THIS run's topic, or null/undefined when the authority is dark. */
38
42
  liveness: {
39
43
  enabled: boolean;
40
44
  dryRun: boolean;
@@ -71,7 +75,7 @@ export interface BoundRun {
71
75
  /** Open runs that have sat in 'preparing' too long and have not been reported yet. */
72
76
  export declare function findStuckPreparingRuns(runs: readonly AutonomousRunRecord[], opts: {
73
77
  nowMs: number;
74
- boundRun?: BoundRun | null;
78
+ boundRun?: BoundRun | readonly BoundRun[] | null;
75
79
  afterMs?: number;
76
80
  afterBoundMs?: number;
77
81
  }): AutonomousRunRecord[];
@@ -82,6 +86,8 @@ export interface PreparingRunWatchdogDeps {
82
86
  notify: (topicId: string, text: string) => Promise<boolean>;
83
87
  /** The run the liveness authority currently evaluates (non-terminal), if any. */
84
88
  boundRun?: () => BoundRun | null;
89
+ /** Every run the liveness authority currently evaluates (one per topic). Wins over `boundRun`. */
90
+ boundRuns?: () => readonly BoundRun[];
85
91
  now?: () => number;
86
92
  }
87
93
  export declare class PreparingRunWatchdog {
@@ -1 +1 @@
1
- {"version":3,"file":"AutonomousStartAdmission.d.ts","sourceRoot":"","sources":["../../src/core/AutonomousStartAdmission.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,KAAK,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAEvF,0EAA0E;AAC1E,eAAO,MAAM,4BAA4B,EAAE,SAAS,MAAM,EAEzD,CAAC;AAGF;;;;GAIG;AACH,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,GACtD,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAOrD;AAED,MAAM,WAAW,mBAAmB;IAClC,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,yFAAyF;IACzF,QAAQ,EAAE;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,MAAM,EAAE,OAAO,CAAC;QAAC,KAAK,EAAE;YAAE,OAAO,EAAE,MAAM,CAAC;YAAC,QAAQ,EAAE,MAAM,CAAC;YAAC,MAAM,EAAE,MAAM,CAAA;SAAE,GAAG,IAAI,CAAA;KAAE,GAAG,IAAI,GAAG,SAAS,CAAC;IACxI,sEAAsE;IACtE,YAAY,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,eAAe,CAAC,EAAE,MAAM,CAAC;QAAC,kBAAkB,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,GAAG,SAAS,CAAC;IAC5H,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,sBAAsB;IACrC,aAAa,EAAE,WAAW,GAAG,QAAQ,CAAC;IACtC,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,wBAAgB,2BAA2B,CAAC,KAAK,EAAE,mBAAmB,GAAG,sBAAsB,CAuB9F;AAED,eAAO,MAAM,yBAAyB,QAAa,CAAC;AACpD,iGAAiG;AACjG,eAAO,MAAM,+BAA+B,QAAc,CAAC;AAC3D,yFAAyF;AACzF,eAAO,MAAM,6BAA6B,IAAI,CAAC;AAE/C,MAAM,WAAW,QAAQ;IAAG,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE;AAE7E,sFAAsF;AACtF,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,SAAS,mBAAmB,EAAE,EACpC,IAAI,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,QAAQ,GAAG,IAAI,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,YAAY,CAAC,EAAE,MAAM,CAAA;CAAE,GAC3F,mBAAmB,EAAE,CAcvB;AAED,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,mBAAmB,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAOrF;AAED,MAAM,WAAW,wBAAwB;IACvC,KAAK,EAAE,IAAI,CAAC,kBAAkB,EAAE,UAAU,GAAG,QAAQ,CAAC,CAAC;IACvD,iFAAiF;IACjF,MAAM,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAC5D,iFAAiF;IACjF,QAAQ,CAAC,EAAE,MAAM,QAAQ,GAAG,IAAI,CAAC;IACjC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACpB;AAED,qBAAa,oBAAoB;IAEnB,OAAO,CAAC,QAAQ,CAAC,IAAI;IADjC,OAAO,CAAC,OAAO,CAAS;IACxB,YAA6B,IAAI,EAAE,wBAAwB,EAAI;IAE/D,wDAAwD;IAClD,IAAI,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC,CAmD9B;CACF"}
1
+ {"version":3,"file":"AutonomousStartAdmission.d.ts","sourceRoot":"","sources":["../../src/core/AutonomousStartAdmission.ts"],"names":[],"mappings":"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"}
@@ -12,14 +12,18 @@
12
12
  *
13
13
  * THE FIX:
14
14
  * 1. `decideAutonomousStartStatus` — 'preparing' only while a W32 window
15
- * lifecycle is genuinely open AND its single liveness slot can take this
16
- * run. Every other run starts 'active', so the reconciler revives it if its
15
+ * lifecycle is genuinely open AND this topic's liveness binding can take
16
+ * this run. Every other run starts 'active', so the reconciler revives it if its
17
17
  * session dies.
18
18
  * 2. `PreparingRunWatchdog` — any open run still 'preparing' past a few
19
19
  * minutes gets ONE plain notice in its own topic. A run that cannot start
20
20
  * is never silent. At most PREPARING_NOTICE_MAX_ATTEMPTS sends per run,
21
21
  * counted on the durable run record, so a dead delivery path cannot loop.
22
22
  *
23
+ * Liveness holds one binding PER TOPIC (2026-11-01, topic 10000001256): it
24
+ * used to hold one binding for the whole agent, so a run in one topic left a
25
+ * run in another 'preparing' with nothing able to promote it.
26
+ *
23
27
  * @self-action-controller: preparing-run-watchdog
24
28
  */
25
29
  /** Lifecycle states in which a W32 window is admitting / running work. */
@@ -53,10 +57,10 @@ export function decideAutonomousStartStatus(input) {
53
57
  && (!Number.isFinite(ceilingMs) || input.nowMs < ceilingMs);
54
58
  if (!windowOpen)
55
59
  return { initialStatus: 'active', reason: 'no-open-window' };
56
- // The authority holds ONE binding, and only a NEW run can bind it: a live
57
- // binding (even this topic's, which belongs to an earlier run) refuses it, and
58
- // a finished binding for this same window closes the window to rebinding. A
59
- // run that cannot take the slot could never be promoted, so it must not wait.
60
+ // The authority holds one binding per topic, and only a NEW run can bind it: a
61
+ // live binding in this topic (an earlier run's) refuses it, and a finished
62
+ // binding for this same window closes the window to rebinding. A run that
63
+ // cannot take its topic's binding could never be promoted, so it must not wait.
60
64
  const bound = liveness.state;
61
65
  if (bound && !TERMINAL_LIVENESS_STATES.includes(bound.status)) {
62
66
  return { initialStatus: 'active', reason: 'liveness-slot-held' };
@@ -75,6 +79,7 @@ export const PREPARING_NOTICE_MAX_ATTEMPTS = 3;
75
79
  export function findStuckPreparingRuns(runs, opts) {
76
80
  const afterMs = opts.afterMs ?? PREPARING_NOTICE_AFTER_MS;
77
81
  const afterBoundMs = opts.afterBoundMs ?? PREPARING_NOTICE_AFTER_BOUND_MS;
82
+ const bounds = !opts.boundRun ? [] : Array.isArray(opts.boundRun) ? opts.boundRun : [opts.boundRun];
78
83
  return runs.filter((run) => {
79
84
  if (run.status !== 'preparing' || run.preparingNoticeAt)
80
85
  return false;
@@ -83,11 +88,11 @@ export function findStuckPreparingRuns(runs, opts) {
83
88
  const registeredMs = Date.parse(run.registeredAt);
84
89
  if (!Number.isFinite(registeredMs))
85
90
  return true;
86
- const bound = opts.boundRun?.topicId === run.topicId && opts.boundRun.runId === run.runId;
91
+ const bound = bounds.find(entry => entry.topicId === run.topicId && entry.runId === run.runId);
87
92
  if (!bound)
88
93
  return opts.nowMs - registeredMs >= afterMs;
89
94
  // The allowance for a first work receipt runs from when the authority took the run.
90
- const boundMs = Date.parse(opts.boundRun.boundAt);
95
+ const boundMs = Date.parse(bound.boundAt);
91
96
  return opts.nowMs - Math.max(registeredMs, Number.isFinite(boundMs) ? boundMs : registeredMs) >= afterBoundMs;
92
97
  });
93
98
  }
@@ -112,7 +117,7 @@ export class PreparingRunWatchdog {
112
117
  this.running = true;
113
118
  try {
114
119
  const nowMs = this.deps.now?.() ?? Date.now();
115
- const stuck = findStuckPreparingRuns(this.deps.store.listOpen(nowMs), { nowMs, boundRun: this.deps.boundRun?.() ?? null });
120
+ const stuck = findStuckPreparingRuns(this.deps.store.listOpen(nowMs), { nowMs, boundRun: this.deps.boundRuns?.() ?? this.deps.boundRun?.() ?? null });
116
121
  const reported = [];
117
122
  for (const run of stuck) {
118
123
  // Claim under the run lock, re-checking the live record: a run promoted
@@ -1 +1 @@
1
- {"version":3,"file":"AutonomousStartAdmission.js","sourceRoot":"","sources":["../../src/core/AutonomousStartAdmission.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"AutonomousStartAdmission.js","sourceRoot":"","sources":["../../src/core/AutonomousStartAdmission.ts"],"names":[],"mappings":"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"}
@@ -28,6 +28,11 @@ export type DesktopInput = {
28
28
  } | {
29
29
  kind: 'keyDown' | 'keyUp';
30
30
  key: DesktopKey;
31
+ }
32
+ /** Handled by the grant authority, never by host.input. null = host default. */
33
+ | {
34
+ kind: 'selectDisplay';
35
+ displayId: string | null;
31
36
  };
32
37
  /** Every key a viewer may hold or tap. Shared by the browser viewer, the
33
38
  * native app and both host helpers, which each map the same names. */
@@ -52,7 +57,32 @@ export interface DesktopProbe {
52
57
  screenGrant?: 'own' | 'inherited' | 'none';
53
58
  inputGrant?: 'own' | 'inherited' | 'none';
54
59
  }
60
+ export type DesktopPlatform = 'macos' | 'windows';
61
+ export interface DesktopDisplay {
62
+ /** Opaque to viewers; the host resolves it. */
63
+ id: string;
64
+ name: string;
65
+ /** Real pixels. */
66
+ width: number;
67
+ height: number;
68
+ main: boolean;
69
+ }
70
+ export interface DesktopDisplayList {
71
+ displays: DesktopDisplay[];
72
+ /** null only where canShowAll is true: every screen in one picture. */
73
+ currentDisplayId: string | null;
74
+ canShowAll: boolean;
75
+ }
76
+ export declare function validDisplayId(value: unknown): value is string;
77
+ /** Host helpers report untrusted text. Bound it before any viewer sees it. */
78
+ export declare function parseDesktopDisplays(raw: unknown): DesktopDisplay[];
55
79
  export interface DesktopHost {
80
+ /** Absent on a host that cannot tell a viewer which shortcuts apply. */
81
+ readonly platform?: DesktopPlatform;
82
+ /** Absent, or rejecting, means this host cannot switch screens. */
83
+ listDisplays?(): Promise<DesktopDisplayList>;
84
+ /** False when the display is not on this machine; the current one stays. */
85
+ selectDisplay?(displayId: string | null): Promise<boolean>;
56
86
  probe(): Promise<DesktopProbe>;
57
87
  requestPermission?(): Promise<{
58
88
  screenPermission: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"DesktopHost.d.ts","sourceRoot":"","sources":["../../src/core/DesktopHost.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"DesktopHost.d.ts","sourceRoot":"","sources":["../../src/core/DesktopHost.ts"],"names":[],"mappings":"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"}
@@ -41,4 +41,28 @@ export function validDesktopInput(action) {
41
41
  return action.kind === 'type' && typeof action.text === 'string'
42
42
  && action.text.length > 0 && action.text.length <= 1_024 && !action.text.includes('\0');
43
43
  }
44
+ const DISPLAY_ID = /^[A-Za-z0-9_-]{1,32}$/;
45
+ const MAX_DISPLAYS = 16;
46
+ export function validDisplayId(value) {
47
+ return typeof value === 'string' && DISPLAY_ID.test(value);
48
+ }
49
+ /** Host helpers report untrusted text. Bound it before any viewer sees it. */
50
+ export function parseDesktopDisplays(raw) {
51
+ const rows = raw?.displays;
52
+ if (!Array.isArray(rows) || rows.length > MAX_DISPLAYS)
53
+ throw new Error('desktop-displays-invalid');
54
+ const seen = new Set();
55
+ return rows.map((row, index) => {
56
+ const { id, name, width, height, main } = (row ?? {});
57
+ if (!validDisplayId(id) || seen.has(id) || !Number.isSafeInteger(width) || !Number.isSafeInteger(height)
58
+ || width < 1 || width > 65_535
59
+ || height < 1 || height > 65_535 || typeof main !== 'boolean') {
60
+ throw new Error('desktop-displays-invalid');
61
+ }
62
+ seen.add(id);
63
+ const label = typeof name === 'string'
64
+ ? [...name].map(c => (c.charCodeAt(0) < 32 || c.charCodeAt(0) === 127 ? ' ' : c)).join('').trim().slice(0, 64) : '';
65
+ return { id, name: label || `Display ${index + 1}`, width: width, height: height, main };
66
+ });
67
+ }
44
68
  //# sourceMappingURL=DesktopHost.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"DesktopHost.js","sourceRoot":"","sources":["../../src/core/DesktopHost.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"DesktopHost.js","sourceRoot":"","sources":["../../src/core/DesktopHost.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import type { IncomingMessage } from 'node:http';
2
- import type { DesktopHost, DesktopProbe } from './DesktopHost.js';
2
+ import { type DesktopDisplay, type DesktopHost, type DesktopPlatform, type DesktopProbe } from './DesktopHost.js';
3
3
  import type { RemoteStepUpLockoutPort } from './RemoteStepUpLockouts.js';
4
4
  import type { DesktopStreamSession } from '../server/DesktopStreamManager.js';
5
5
  import type { DesktopAccessAudit } from './DesktopAccessAudit.js';
@@ -15,6 +15,15 @@ export interface DirectDesktopRequestInput {
15
15
  previousVideoCodec?: 'jpeg' | 'h264';
16
16
  scopeConfirmed: boolean;
17
17
  }
18
+ export interface DesktopDisplaysReply {
19
+ /** false: this host cannot switch screens, and selectDisplay must not be sent. */
20
+ supported: boolean;
21
+ /** Which shortcuts apply. null: unknown, so the viewer sends none. */
22
+ platform: DesktopPlatform | null;
23
+ displays: DesktopDisplay[];
24
+ currentDisplayId: string | null;
25
+ canShowAll: boolean;
26
+ }
18
27
  export interface DesktopTargetIdentity {
19
28
  /** DER SPKI Ed25519 public key pinned to this physical machine. */
20
29
  publicKey: Buffer;
@@ -88,6 +97,7 @@ export declare class DirectDesktopAccess {
88
97
  x: number;
89
98
  y: number;
90
99
  }>;
100
+ displays(requestId: string, operatorSessionToken: string): Promise<DesktopDisplaysReply>;
91
101
  ticket(requestId: string, operatorSessionToken: string, nonce: string, signature: string): string;
92
102
  admit(request: IncomingMessage): Promise<DesktopStreamSession>;
93
103
  revoke(requestId: string, operatorSessionToken: string): void;