instar 1.3.1592 → 1.3.1594
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.
- package/dashboard/console/console.css +1 -0
- package/dashboard/console/sessions.js +1 -1
- package/dashboard/desktop.css +1 -0
- package/dashboard/desktop.html +7 -0
- package/dashboard/desktop.js +205 -6
- package/dist/commands/server.d.ts.map +1 -1
- package/dist/commands/server.js +3 -0
- package/dist/commands/server.js.map +1 -1
- package/dist/core/AppConversationService.d.ts +38 -0
- package/dist/core/AppConversationService.d.ts.map +1 -1
- package/dist/core/AppConversationService.js +145 -4
- package/dist/core/AppConversationService.js.map +1 -1
- package/dist/core/AppConversationStore.d.ts +60 -2
- package/dist/core/AppConversationStore.d.ts.map +1 -1
- package/dist/core/AppConversationStore.js +142 -7
- package/dist/core/AppConversationStore.js.map +1 -1
- package/dist/core/AppConversationsReplicatedStore.js +1 -1
- package/dist/core/AppConversationsReplicatedStore.js.map +1 -1
- package/dist/core/AppMediaStore.d.ts +186 -0
- package/dist/core/AppMediaStore.d.ts.map +1 -0
- package/dist/core/AppMediaStore.js +805 -0
- package/dist/core/AppMediaStore.js.map +1 -0
- package/dist/core/AppRecordSignatures.d.ts +11 -0
- package/dist/core/AppRecordSignatures.d.ts.map +1 -1
- package/dist/core/AppRecordSignatures.js +33 -3
- package/dist/core/AppRecordSignatures.js.map +1 -1
- package/dist/core/AppReplyRelayInstaller.d.ts +4 -0
- package/dist/core/AppReplyRelayInstaller.d.ts.map +1 -1
- package/dist/core/AppReplyRelayInstaller.js +17 -3
- package/dist/core/AppReplyRelayInstaller.js.map +1 -1
- package/dist/core/AutonomousStartAdmission.d.ts +10 -4
- package/dist/core/AutonomousStartAdmission.d.ts.map +1 -1
- package/dist/core/AutonomousStartAdmission.js +14 -9
- package/dist/core/AutonomousStartAdmission.js.map +1 -1
- package/dist/core/DesktopHost.d.ts +30 -0
- package/dist/core/DesktopHost.d.ts.map +1 -1
- package/dist/core/DesktopHost.js +24 -0
- package/dist/core/DesktopHost.js.map +1 -1
- package/dist/core/DirectDesktopAccess.d.ts +11 -1
- package/dist/core/DirectDesktopAccess.d.ts.map +1 -1
- package/dist/core/DirectDesktopAccess.js +46 -0
- package/dist/core/DirectDesktopAccess.js.map +1 -1
- package/dist/core/FileClassifier.d.ts.map +1 -1
- package/dist/core/FileClassifier.js +1 -0
- package/dist/core/FileClassifier.js.map +1 -1
- package/dist/core/InstarWorktreeManager.js +1 -1
- package/dist/core/InstarWorktreeManager.js.map +1 -1
- package/dist/core/MacDesktopHost.d.ts +12 -1
- package/dist/core/MacDesktopHost.d.ts.map +1 -1
- package/dist/core/MacDesktopHost.js +70 -6
- package/dist/core/MacDesktopHost.js.map +1 -1
- package/dist/core/MobileChatRequests.d.ts.map +1 -1
- package/dist/core/MobileChatRequests.js +3 -0
- package/dist/core/MobileChatRequests.js.map +1 -1
- package/dist/core/MobileDeviceKeys.d.ts +8 -2
- package/dist/core/MobileDeviceKeys.d.ts.map +1 -1
- package/dist/core/MobileDeviceKeys.js +10 -4
- package/dist/core/MobileDeviceKeys.js.map +1 -1
- package/dist/core/PostUpdateMigrator.d.ts +6 -0
- package/dist/core/PostUpdateMigrator.d.ts.map +1 -1
- package/dist/core/PostUpdateMigrator.js +34 -1
- package/dist/core/PostUpdateMigrator.js.map +1 -1
- package/dist/core/WindowRunCadenceExecutor.d.ts +24 -4
- package/dist/core/WindowRunCadenceExecutor.d.ts.map +1 -1
- package/dist/core/WindowRunCadenceExecutor.js +138 -18
- package/dist/core/WindowRunCadenceExecutor.js.map +1 -1
- package/dist/core/WindowRunLivenessAuthority.d.ts +48 -4
- package/dist/core/WindowRunLivenessAuthority.d.ts.map +1 -1
- package/dist/core/WindowRunLivenessAuthority.js +186 -30
- package/dist/core/WindowRunLivenessAuthority.js.map +1 -1
- package/dist/core/WindowsDesktopHost.d.ts +9 -1
- package/dist/core/WindowsDesktopHost.d.ts.map +1 -1
- package/dist/core/WindowsDesktopHost.js +43 -4
- package/dist/core/WindowsDesktopHost.js.map +1 -1
- package/dist/core/WindowsDesktopLocalTransport.js +1 -1
- package/dist/core/WindowsDesktopLocalTransport.js.map +1 -1
- package/dist/core/WriteDomainRegistry.d.ts.map +1 -1
- package/dist/core/WriteDomainRegistry.js +11 -0
- package/dist/core/WriteDomainRegistry.js.map +1 -1
- package/dist/core/appInboundDispatch.d.ts.map +1 -1
- package/dist/core/appInboundDispatch.js +11 -2
- package/dist/core/appInboundDispatch.js.map +1 -1
- package/dist/core/appMediaReplyFiles.d.ts +34 -0
- package/dist/core/appMediaReplyFiles.d.ts.map +1 -0
- package/dist/core/appMediaReplyFiles.js +172 -0
- package/dist/core/appMediaReplyFiles.js.map +1 -0
- package/dist/core/appMediaTypes.d.ts +64 -0
- package/dist/core/appMediaTypes.d.ts.map +1 -0
- package/dist/core/appMediaTypes.js +192 -0
- package/dist/core/appMediaTypes.js.map +1 -0
- package/dist/core/appMediaWorker.d.ts +19 -0
- package/dist/core/appMediaWorker.d.ts.map +1 -0
- package/dist/core/appMediaWorker.js +162 -0
- package/dist/core/appMediaWorker.js.map +1 -0
- package/dist/core/devGatedFeatures.d.ts.map +1 -1
- package/dist/core/devGatedFeatures.js +6 -0
- package/dist/core/devGatedFeatures.js.map +1 -1
- package/dist/core/types.d.ts +9 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js.map +1 -1
- package/dist/data/standards-guard-index.json +1 -1
- package/dist/data/standards-guard-index.meta.json +2 -2
- package/dist/data/standards-registry.meta.json +1 -1
- package/dist/monitoring/templates-drift-verifier.d.ts.map +1 -1
- package/dist/monitoring/templates-drift-verifier.js +6 -1
- package/dist/monitoring/templates-drift-verifier.js.map +1 -1
- package/dist/native/instar-desktop-host +0 -0
- package/dist/native/windows/InstarDesktopCompanion.cs +84 -16
- package/dist/scaffold/templates.d.ts.map +1 -1
- package/dist/scaffold/templates.js +3 -2
- package/dist/scaffold/templates.js.map +1 -1
- package/dist/server/AgentServer.d.ts.map +1 -1
- package/dist/server/AgentServer.js +15 -8
- package/dist/server/AgentServer.js.map +1 -1
- package/dist/server/CapabilityIndex.js +3 -3
- package/dist/server/CapabilityIndex.js.map +1 -1
- package/dist/server/DesktopMeshBroker.d.ts +1 -1
- package/dist/server/DesktopMeshBroker.d.ts.map +1 -1
- package/dist/server/DesktopMeshBroker.js.map +1 -1
- package/dist/server/DesktopStreamManager.d.ts +16 -0
- package/dist/server/DesktopStreamManager.d.ts.map +1 -1
- package/dist/server/DesktopStreamManager.js +39 -1
- package/dist/server/DesktopStreamManager.js.map +1 -1
- package/dist/server/mobileConversationRoutes.d.ts +5 -2
- package/dist/server/mobileConversationRoutes.d.ts.map +1 -1
- package/dist/server/mobileConversationRoutes.js +186 -24
- package/dist/server/mobileConversationRoutes.js.map +1 -1
- package/dist/server/mobileMediaRoutes.d.ts +12 -0
- package/dist/server/mobileMediaRoutes.d.ts.map +1 -0
- package/dist/server/mobileMediaRoutes.js +337 -0
- package/dist/server/mobileMediaRoutes.js.map +1 -0
- package/dist/server/mobilePairingRoutes.d.ts +5 -0
- package/dist/server/mobilePairingRoutes.d.ts.map +1 -1
- package/dist/server/mobilePairingRoutes.js +43 -2
- package/dist/server/mobilePairingRoutes.js.map +1 -1
- package/dist/server/routes.d.ts.map +1 -1
- package/dist/server/routes.js +218 -33
- package/dist/server/routes.js.map +1 -1
- package/dist/testing/selfActionRegistry.d.ts.map +1 -1
- package/dist/testing/selfActionRegistry.js +33 -0
- package/dist/testing/selfActionRegistry.js.map +1 -1
- package/package.json +1 -1
- package/scripts/blocking-decision-surfaces-baseline.json +2 -2
- package/scripts/windows-desktop-local-transport.ps1 +2 -2
- package/src/data/builtin-manifest.json +74 -66
- package/src/data/standards-guard-index.json +1 -1
- package/src/data/standards-guard-index.meta.json +2 -2
- package/src/data/standards-registry.meta.json +1 -1
- package/src/data/state-coherence-registry.json +40 -0
- package/src/scaffold/templates.ts +3 -2
- package/src/templates/scripts/app-media-path +58 -0
- package/src/templates/scripts/app-reply.sh +65 -4
- package/upgrades/1.3.1593.md +53 -0
- package/upgrades/1.3.1594.md +31 -0
- package/upgrades/side-effects/console-composer-placeholder.eli16.md +7 -0
- package/upgrades/side-effects/console-composer-placeholder.md +31 -0
- package/upgrades/side-effects/desktop-multi-display-gestures.md +73 -0
- package/upgrades/side-effects/desktop-stream-frame-stats.md +45 -0
- package/upgrades/side-effects/mobile-native-chat-media-inc1.md +146 -0
- package/upgrades/side-effects/window-run-liveness-per-topic.eli16.md +28 -0
- package/upgrades/side-effects/window-run-liveness-per-topic.md +81 -0
- package/upgrades/1.3.1592.md +0 -22
|
@@ -1009,6 +1009,7 @@ button.run-mark:focus-visible { outline: 2px solid var(--accent); outline-offset
|
|
|
1009
1009
|
.sess-resume { position: absolute; bottom: 12px; left: 50%; transform: translateX(-50%); z-index: 2; }
|
|
1010
1010
|
.sess-composer { display: flex; gap: var(--s-2); align-items: flex-end; position: sticky; bottom: 0; padding: var(--s-2) 0; background: var(--bg); }
|
|
1011
1011
|
.sess-input { flex: 1; min-height: 44px; font-size: 16px; resize: none; }
|
|
1012
|
+
.sess-input::placeholder { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
|
1012
1013
|
.sess-composer-btns { display: flex; gap: var(--s-2); }
|
|
1013
1014
|
.sess-attach { min-width: 44px; min-height: 44px; padding: 0 10px; font-size: 18px; }
|
|
1014
1015
|
.sess-attach:disabled { opacity: .45; cursor: not-allowed; }
|
|
@@ -239,7 +239,7 @@ function openView(box, row) {
|
|
|
239
239
|
const termBox = el('div', { class: 'sess-term', 'aria-label': 'Live terminal' });
|
|
240
240
|
const resume = el('button', { class: 'btn-primary btn-inline sess-resume', type: 'button', text: '▼ Back to live', hidden: true });
|
|
241
241
|
const more = el('button', { class: 'btn-quiet sess-more', type: 'button', 'aria-label': 'More', text: '⋯', 'data-more': '1' });
|
|
242
|
-
const input = el('textarea', { class: 'reason-input sess-input', rows: '1', placeholder: '
|
|
242
|
+
const input = el('textarea', { class: 'reason-input sess-input', rows: '1', placeholder: 'Message…', 'aria-label': 'Message to the session' });
|
|
243
243
|
const sendBtn = el('button', { class: 'btn-primary btn-inline', type: 'button', text: 'Send', 'data-send': '1' });
|
|
244
244
|
const keysBtn = el('button', { class: 'btn-quiet', type: 'button', text: 'Keys', 'aria-expanded': 'false', 'data-keys': '1' });
|
|
245
245
|
// Attach: a screenshot or file, picked, pasted or dropped. Saved on this machine, so a
|
package/dashboard/desktop.css
CHANGED
|
@@ -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}
|
package/dashboard/desktop.html
CHANGED
|
@@ -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>
|
package/dashboard/desktop.js
CHANGED
|
@@ -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 (
|
|
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 &&
|
|
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
|
-
|
|
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);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/commands/server.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/commands/server.ts"],"names":[],"mappings":"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"}
|
package/dist/commands/server.js
CHANGED
|
@@ -8658,6 +8658,9 @@ export async function startServer(options) {
|
|
|
8658
8658
|
}
|
|
8659
8659
|
catch { /* @silent-fallback-ok — the stop record is observability */ }
|
|
8660
8660
|
},
|
|
8661
|
+
mediaMaxStoreBytes: () => config.mobilePairing?.native?.media?.maxStoreBytes,
|
|
8662
|
+
raiseAttention: (item) => { void telegram?.createAttentionItem({ id: item.conditionKey, conditionKey: item.conditionKey, title: item.title, summary: item.body, category: 'general', priority: 'NORMAL', sourceContext: 'app-media' }); },
|
|
8663
|
+
clearAttention: (conditionKey) => { telegram?.clearAttentionCondition({ conditionKey }, 'cleared: the app media store has room again'); },
|
|
8661
8664
|
reportDegradation: (what, detail) => degradationReporter.report({
|
|
8662
8665
|
feature: what, primary: 'record and deliver native app conversations', fallback: 'the request was refused or reported outcome-unknown',
|
|
8663
8666
|
reason: detail, impact: 'An app conversation step needs attention.',
|