mindexec-ai 0.2.385

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 (99) hide show
  1. package/README.md +354 -0
  2. package/codex-runtime.js +1339 -0
  3. package/launch-bridge.cjs +236 -0
  4. package/package.json +77 -0
  5. package/port-guard.cjs +232 -0
  6. package/remote-fast/osx-arm64/mindexec-remote-fast +0 -0
  7. package/remote-fast/osx-arm64/mindexec-remote-fast.deps.json +24 -0
  8. package/remote-fast/osx-arm64/mindexec-remote-fast.dll +0 -0
  9. package/remote-fast/osx-arm64/mindexec-remote-fast.runtimeconfig.json +13 -0
  10. package/remote-fast/osx-x64/mindexec-remote-fast +0 -0
  11. package/remote-fast/osx-x64/mindexec-remote-fast.deps.json +24 -0
  12. package/remote-fast/osx-x64/mindexec-remote-fast.dll +0 -0
  13. package/remote-fast/osx-x64/mindexec-remote-fast.runtimeconfig.json +13 -0
  14. package/remote-fast/win-x64/mindexec-remote-fast.deps.json +24 -0
  15. package/remote-fast/win-x64/mindexec-remote-fast.dll +0 -0
  16. package/remote-fast/win-x64/mindexec-remote-fast.exe +0 -0
  17. package/remote-fast/win-x64/mindexec-remote-fast.runtimeconfig.json +20 -0
  18. package/remote-hub.js +3106 -0
  19. package/scripts/auth-session-smoke.mjs +262 -0
  20. package/scripts/remote-agent-managed-smoke.mjs +291 -0
  21. package/scripts/remote-agent-package-smoke.mjs +64 -0
  22. package/scripts/remote-agent-ws-smoke.mjs +202 -0
  23. package/scripts/remote-fast-live-rate-smoke.mjs +355 -0
  24. package/scripts/remote-fast-mdm-browser-smoke.mjs +476 -0
  25. package/scripts/remote-fleet-render-smoke.mjs +1491 -0
  26. package/scripts/remote-frame-ws-smoke.mjs +234 -0
  27. package/scripts/remote-http-smoke.mjs +592 -0
  28. package/scripts/remote-hub-identity-smoke.mjs +146 -0
  29. package/scripts/remote-hub-scale-smoke.mjs +124 -0
  30. package/scripts/remote-hub-smoke.mjs +631 -0
  31. package/scripts/remote-input-ws-smoke.mjs +263 -0
  32. package/scripts/remote-registry-follower-smoke.mjs +752 -0
  33. package/scripts/setup-tree-sitter-grammars.mjs +80 -0
  34. package/server.js +15709 -0
  35. package/start-bridge.bat +32 -0
  36. package/start-bridge.sh +81 -0
  37. package/tree-sitter-grammars/README.md +18 -0
  38. package/tree-sitter-grammars/tree-sitter-c_sharp.wasm +0 -0
  39. package/tree-sitter-grammars/tree-sitter-go.wasm +0 -0
  40. package/tree-sitter-grammars/tree-sitter-java.wasm +0 -0
  41. package/tree-sitter-grammars/tree-sitter-javascript.wasm +0 -0
  42. package/tree-sitter-grammars/tree-sitter-python.wasm +0 -0
  43. package/tree-sitter-grammars/tree-sitter-rust.wasm +0 -0
  44. package/tree-sitter-grammars/tree-sitter-tsx.wasm +0 -0
  45. package/tree-sitter-grammars/tree-sitter-typescript.wasm +0 -0
  46. package/wwwroot/_headers +73 -0
  47. package/wwwroot/_redirects +1 -0
  48. package/wwwroot/appsettings.json +83 -0
  49. package/wwwroot/assets/AdminDashboardPage-B2vz2Px9.css +1 -0
  50. package/wwwroot/assets/AdminDashboardPage-DnuCHywn.js +1 -0
  51. package/wwwroot/assets/AppSidebar-DU2OgSiv.js +2 -0
  52. package/wwwroot/assets/AuthPages-BrH6kRcv.css +1 -0
  53. package/wwwroot/assets/AuthPages-Dgezl7Vj.js +1 -0
  54. package/wwwroot/assets/CodePage-7kgZlB3O.js +87 -0
  55. package/wwwroot/assets/CodePage-Bncc352E.css +1 -0
  56. package/wwwroot/assets/CompanyCorePage-ChBnq1ve.css +1 -0
  57. package/wwwroot/assets/CompanyCorePage-CzIZIIU_.js +13 -0
  58. package/wwwroot/assets/ExecutionModePage-B-etp_mc.js +18 -0
  59. package/wwwroot/assets/ExecutionModePage-TLuld9l3.css +1 -0
  60. package/wwwroot/assets/LaunchLeadCapture-Bx9LM0IX.js +1 -0
  61. package/wwwroot/assets/LaunchLeadCapture-CiRI1shz.css +1 -0
  62. package/wwwroot/assets/MarketingHome-BsyerRpe.js +1 -0
  63. package/wwwroot/assets/MarketingHome-DPzaYzA_.css +1 -0
  64. package/wwwroot/assets/MindCanvas-DtqOZnoW.css +1 -0
  65. package/wwwroot/assets/MindCanvas-zEDXzaxW.js +49 -0
  66. package/wwwroot/assets/PlanMasterPage-CJ36rep-.css +1 -0
  67. package/wwwroot/assets/PlanMasterPage-NZ_mPvaE.js +4 -0
  68. package/wwwroot/assets/PricingPage-Cg_0i_ZR.css +1 -0
  69. package/wwwroot/assets/PricingPage-Ylrn8l2g.js +1 -0
  70. package/wwwroot/assets/ToolPages-3M2KqA9k.js +28 -0
  71. package/wwwroot/assets/ToolPages-DIB187pZ.css +1 -0
  72. package/wwwroot/assets/YouTubeSearchPage-COv1oAA7.js +4 -0
  73. package/wwwroot/assets/YouTubeSearchPage-IPPa_BIH.css +1 -0
  74. package/wwwroot/assets/app-runtime-xD2Z3NdN.js +1 -0
  75. package/wwwroot/assets/canvas-runtime-BbicBcOj.js +44 -0
  76. package/wwwroot/assets/code-agent-runtime-B5PPZd1t.js +74 -0
  77. package/wwwroot/assets/executionModeSettings-NJqurj-o.js +1 -0
  78. package/wwwroot/assets/index-CQMKCp-t.js +2 -0
  79. package/wwwroot/assets/index-yNpEK-gp.css +1 -0
  80. package/wwwroot/assets/marketingTools-DN_rnHeB.js +4 -0
  81. package/wwwroot/assets/mindCanvasSearchWorker-BzPMsHOB.js +1 -0
  82. package/wwwroot/assets/mindexecution-mindcanvas.png +0 -0
  83. package/wwwroot/assets/mindexecution-prod-home-current.png +0 -0
  84. package/wwwroot/assets/mindexecution-prod-pricing-current.png +0 -0
  85. package/wwwroot/assets/pricingCheckoutShell-O-DnwmbU.js +1 -0
  86. package/wwwroot/assets/productionAdapterConfig-C5jfk6oG.js +1 -0
  87. package/wwwroot/assets/runtimeSettingsPersistenceProjection-BoNWmYjU.js +1 -0
  88. package/wwwroot/assets/storage-TM3YrWaj.js +1 -0
  89. package/wwwroot/assets/supabaseAuthAdapter-DA43DeSY.js +44 -0
  90. package/wwwroot/assets/toolHandoff-D5e5f7t5.js +4 -0
  91. package/wwwroot/assets/vendor-icons-DE3gIReG.js +681 -0
  92. package/wwwroot/assets/vendor-msgpack-BE8aAsr3.js +1 -0
  93. package/wwwroot/assets/vendor-react-BXzpOyCS.js +40 -0
  94. package/wwwroot/favicon.svg +7 -0
  95. package/wwwroot/index.html +22 -0
  96. package/wwwroot/manifest.webmanifest +19 -0
  97. package/wwwroot/robots.txt +4 -0
  98. package/wwwroot/service-worker.js +7 -0
  99. package/wwwroot/sitemap.xml +39 -0
@@ -0,0 +1,1491 @@
1
+ #!/usr/bin/env node
2
+
3
+ import assert from 'node:assert/strict';
4
+ import fs from 'node:fs/promises';
5
+ import path from 'node:path';
6
+ import vm from 'node:vm';
7
+ import { fileURLToPath } from 'node:url';
8
+ import { createRemoteHub } from '../remote-hub.js';
9
+
10
+ const SYNTHETIC_COUNT = Number(process.env.REMOTE_FLEET_RENDER_SMOKE_COUNT || 500);
11
+
12
+ function dataAttributeToDatasetKey(name) {
13
+ return String(name || '').replace(/^data-/, '').replace(/-([a-z])/g, (_, char) => char.toUpperCase());
14
+ }
15
+
16
+ class MiniStyle {
17
+ constructor() {
18
+ this._cssText = '';
19
+ }
20
+
21
+ get cssText() {
22
+ return this._cssText;
23
+ }
24
+
25
+ set cssText(value) {
26
+ this._cssText = String(value || '');
27
+ const displayMatch = /(?:^|;)\s*display\s*:\s*([^;]+)/i.exec(this._cssText);
28
+ if (displayMatch) {
29
+ this.display = displayMatch[1].trim();
30
+ }
31
+ }
32
+
33
+ setProperty(name, value) {
34
+ this[String(name)] = String(value);
35
+ }
36
+ }
37
+
38
+ class MiniClassList {
39
+ constructor(owner) {
40
+ this.owner = owner;
41
+ this.tokens = new Set();
42
+ }
43
+
44
+ add(...tokens) {
45
+ tokens.forEach(token => {
46
+ const value = String(token || '').trim();
47
+ if (value) {
48
+ this.tokens.add(value);
49
+ }
50
+ });
51
+ this.sync();
52
+ }
53
+
54
+ remove(...tokens) {
55
+ tokens.forEach(token => this.tokens.delete(String(token || '').trim()));
56
+ this.sync();
57
+ }
58
+
59
+ contains(token) {
60
+ return this.tokens.has(String(token || '').trim());
61
+ }
62
+
63
+ toggle(token, force) {
64
+ const value = String(token || '').trim();
65
+ if (!value) return false;
66
+ const shouldAdd = force === undefined ? !this.tokens.has(value) : !!force;
67
+ if (shouldAdd) {
68
+ this.tokens.add(value);
69
+ } else {
70
+ this.tokens.delete(value);
71
+ }
72
+ this.sync();
73
+ return shouldAdd;
74
+ }
75
+
76
+ sync() {
77
+ this.owner.className = [...this.tokens].join(' ');
78
+ }
79
+ }
80
+
81
+ class MiniElement {
82
+ constructor(tagName, ownerDocument) {
83
+ this.tagName = String(tagName || '').toUpperCase();
84
+ this.nodeName = this.tagName;
85
+ this.ownerDocument = ownerDocument;
86
+ this.parentElement = null;
87
+ this.children = [];
88
+ this.attributes = {};
89
+ this.dataset = {};
90
+ this.style = new MiniStyle();
91
+ this.classList = new MiniClassList(this);
92
+ this.className = '';
93
+ this._textContent = '';
94
+ this._listeners = new Map();
95
+ this.value = '';
96
+ this.checked = false;
97
+ this.disabled = false;
98
+ this.clientWidth = 320;
99
+ this.clientHeight = 180;
100
+ this.width = 0;
101
+ this.height = 0;
102
+ }
103
+
104
+ get textContent() {
105
+ return `${this._textContent}${this.children.map(child => child.textContent).join('')}`;
106
+ }
107
+
108
+ set textContent(value) {
109
+ this.children.forEach(child => {
110
+ child.parentElement = null;
111
+ });
112
+ this.children = [];
113
+ this._textContent = String(value ?? '');
114
+ }
115
+
116
+ get innerHTML() {
117
+ return '';
118
+ }
119
+
120
+ set innerHTML(_value) {
121
+ this.children.forEach(child => {
122
+ child.parentElement = null;
123
+ });
124
+ this.children = [];
125
+ this._textContent = '';
126
+ }
127
+
128
+ appendChild(child) {
129
+ if (!child) return child;
130
+ if (child.parentElement) {
131
+ child.parentElement.children = child.parentElement.children.filter(item => item !== child);
132
+ }
133
+ child.parentElement = this;
134
+ this.children.push(child);
135
+ return child;
136
+ }
137
+
138
+ remove() {
139
+ if (!this.parentElement) return;
140
+ this.parentElement.children = this.parentElement.children.filter(child => child !== this);
141
+ this.parentElement = null;
142
+ }
143
+
144
+ setAttribute(name, value) {
145
+ const key = String(name || '');
146
+ const text = String(value ?? '');
147
+ this.attributes[key] = text;
148
+ if (key === 'id') {
149
+ this.id = text;
150
+ } else if (key === 'class') {
151
+ this.className = text;
152
+ this.classList.tokens = new Set(text.split(/\s+/).filter(Boolean));
153
+ } else if (key.startsWith('data-')) {
154
+ this.dataset[dataAttributeToDatasetKey(key)] = text;
155
+ } else if (key === 'aria-label') {
156
+ this.ariaLabel = text;
157
+ }
158
+ }
159
+
160
+ getAttribute(name) {
161
+ const key = String(name || '');
162
+ if (key.startsWith('data-')) {
163
+ return this.dataset[dataAttributeToDatasetKey(key)];
164
+ }
165
+ return this.attributes[key];
166
+ }
167
+
168
+ addEventListener(type, listener) {
169
+ const key = String(type || '');
170
+ if (!this._listeners.has(key)) {
171
+ this._listeners.set(key, []);
172
+ }
173
+ this._listeners.get(key).push(listener);
174
+ }
175
+
176
+ dispatchEvent(event) {
177
+ const payload = typeof event === 'string' ? { type: event } : { ...(event || {}) };
178
+ let immediateStopped = false;
179
+ const originalStopImmediatePropagation = typeof payload.stopImmediatePropagation === 'function'
180
+ ? payload.stopImmediatePropagation
181
+ : null;
182
+ payload.type = payload.type || 'event';
183
+ payload.target = payload.target || this;
184
+ payload.currentTarget = this;
185
+ payload.preventDefault = payload.preventDefault || (() => {});
186
+ payload.stopPropagation = payload.stopPropagation || (() => {});
187
+ payload.stopImmediatePropagation = () => {
188
+ immediateStopped = true;
189
+ originalStopImmediatePropagation?.();
190
+ };
191
+ for (const listener of this._listeners.get(payload.type) || []) {
192
+ listener(payload);
193
+ if (immediateStopped) {
194
+ break;
195
+ }
196
+ }
197
+ return true;
198
+ }
199
+
200
+ focus() {
201
+ this.ownerDocument.activeElement = this;
202
+ }
203
+
204
+ blur() {
205
+ if (this.ownerDocument.activeElement === this) {
206
+ this.ownerDocument.activeElement = null;
207
+ }
208
+ }
209
+
210
+ getBoundingClientRect() {
211
+ return {
212
+ left: 0,
213
+ top: 0,
214
+ right: this.clientWidth,
215
+ bottom: this.clientHeight,
216
+ width: this.clientWidth,
217
+ height: this.clientHeight
218
+ };
219
+ }
220
+
221
+ getContext(type) {
222
+ if (this.tagName !== 'CANVAS' || String(type || '').toLowerCase() !== '2d') {
223
+ return null;
224
+ }
225
+
226
+ if (this._canvasContext) {
227
+ return this._canvasContext;
228
+ }
229
+
230
+ const owner = this.ownerDocument;
231
+ this._canvasContext = {
232
+ imageSmoothingEnabled: false,
233
+ imageSmoothingQuality: 'low',
234
+ fillStyle: '#000',
235
+ clearRect: (...args) => {
236
+ owner.canvasDrawCalls.push({ canvas: this, op: 'clearRect', args });
237
+ },
238
+ fillRect: (...args) => {
239
+ owner.canvasDrawCalls.push({ canvas: this, op: 'fillRect', args });
240
+ },
241
+ drawImage: (...args) => {
242
+ owner.canvasDrawCalls.push({ canvas: this, op: 'drawImage', args });
243
+ }
244
+ };
245
+ return this._canvasContext;
246
+ }
247
+
248
+ querySelector(selector) {
249
+ return this.querySelectorAll(selector)[0] || null;
250
+ }
251
+
252
+ querySelectorAll(selector) {
253
+ const matches = [];
254
+ const visit = element => {
255
+ for (const child of element.children) {
256
+ if (matchesSelector(child, selector)) {
257
+ matches.push(child);
258
+ }
259
+ visit(child);
260
+ }
261
+ };
262
+ visit(this);
263
+ return matches;
264
+ }
265
+
266
+ closest(selector) {
267
+ let current = this;
268
+ while (current) {
269
+ if (matchesSelector(current, selector)) {
270
+ return current;
271
+ }
272
+ current = current.parentElement;
273
+ }
274
+ return null;
275
+ }
276
+
277
+ contains(node) {
278
+ let current = node;
279
+ while (current) {
280
+ if (current === this) return true;
281
+ current = current.parentElement;
282
+ }
283
+ return false;
284
+ }
285
+ }
286
+
287
+ class MiniDocument {
288
+ constructor() {
289
+ this.body = new MiniElement('body', this);
290
+ this.head = new MiniElement('head', this);
291
+ this.canvasDrawCalls = [];
292
+ this.activeElement = null;
293
+ }
294
+
295
+ createElement(tagName) {
296
+ return new MiniElement(tagName, this);
297
+ }
298
+
299
+ getElementById(id) {
300
+ const target = String(id || '');
301
+ return [this.head, this.body]
302
+ .flatMap(root => root.querySelectorAll('*'))
303
+ .find(element => element.id === target) || null;
304
+ }
305
+
306
+ querySelector(selector) {
307
+ return this.body.querySelector(selector) || this.head.querySelector(selector);
308
+ }
309
+
310
+ querySelectorAll(selector) {
311
+ return [
312
+ ...this.head.querySelectorAll(selector),
313
+ ...this.body.querySelectorAll(selector)
314
+ ];
315
+ }
316
+ }
317
+
318
+ function matchesSelector(element, selector) {
319
+ const text = String(selector || '').trim();
320
+ if (!text || !element) return false;
321
+ if (text === '*') return true;
322
+
323
+ const tagMatch = /^[a-zA-Z][\w-]*/.exec(text);
324
+ if (tagMatch && element.tagName.toLowerCase() !== tagMatch[0].toLowerCase()) {
325
+ return false;
326
+ }
327
+
328
+ for (const classMatch of text.matchAll(/\.([\w-]+)/g)) {
329
+ if (!element.classList.contains(classMatch[1])) {
330
+ return false;
331
+ }
332
+ }
333
+
334
+ for (const attrMatch of text.matchAll(/\[([^\]=]+)(?:="([^"]*)")?\]/g)) {
335
+ const attrName = attrMatch[1];
336
+ const expected = attrMatch[2];
337
+ const actual = attrName.startsWith('data-')
338
+ ? element.dataset[dataAttributeToDatasetKey(attrName)]
339
+ : element.getAttribute(attrName);
340
+ if (actual === undefined || actual === null) {
341
+ return false;
342
+ }
343
+ if (expected !== undefined && String(actual) !== expected) {
344
+ return false;
345
+ }
346
+ }
347
+
348
+ return true;
349
+ }
350
+
351
+ function readStatusNumber(status, key) {
352
+ const value = status?.[key];
353
+ return Number.isFinite(Number(value)) ? Number(value) : null;
354
+ }
355
+
356
+ function readLoad1(status) {
357
+ const value = status?.loadavg;
358
+ return Array.isArray(value) && Number.isFinite(Number(value[0])) ? Number(value[0]) : null;
359
+ }
360
+
361
+ function projectDevice(device) {
362
+ const status = device.status || {};
363
+ const capabilities = device.capabilities || {};
364
+ const thumbnail = device.latestThumbnail || {};
365
+ const liveFrame = device.latestLiveFrame || {};
366
+ const liveStream = device.activeLiveStream || {};
367
+ const latestTask = device.latestTask || {};
368
+ const platform = String(status.platform || device.platform || 'unknown');
369
+
370
+ return {
371
+ DeviceId: String(device.deviceId || ''),
372
+ SessionId: String(device.sessionId || ''),
373
+ Name: String(device.deviceName || device.hostname || device.deviceId || 'device'),
374
+ Hostname: String(device.hostname || ''),
375
+ Platform: platform,
376
+ Release: String(status.release || ''),
377
+ Arch: String(device.arch || ''),
378
+ AgentVersion: String(device.agentVersion || ''),
379
+ Connected: device.connected === true,
380
+ ConnectedAt: String(device.connectedAt || ''),
381
+ DisconnectedAt: String(device.disconnectedAt || ''),
382
+ LastSeenAt: String(device.lastSeenAt || ''),
383
+ LastStatusAt: String(device.lastStatusAt || ''),
384
+ LastDisconnectReason: String(device.lastDisconnectReason || ''),
385
+ RemoteAddress: String(device.remoteAddress || ''),
386
+ RemotePort: Number(device.remotePort || 0),
387
+ UptimeSec: readStatusNumber(status, 'uptimeSec'),
388
+ UsedMemRatio: readStatusNumber(status, 'usedMemRatio'),
389
+ Load1: readLoad1(status),
390
+ StatusEnabled: capabilities.status === true,
391
+ ThumbnailEnabled: capabilities.thumbnail === true,
392
+ LiveStreamEnabled: capabilities.liveStream === true,
393
+ ControlEnabled: capabilities.control === true,
394
+ ComputerAgentEnabled: capabilities.computerAgent === true || capabilities.taskDispatch === true,
395
+ AiAssistEnabled: capabilities.aiAssist === true,
396
+ AiModel: String(capabilities.aiModel || ''),
397
+ AiProvider: String(capabilities.aiProvider || ''),
398
+ ThumbnailStreamId: String(thumbnail.streamId || ''),
399
+ ThumbnailFrameSeq: Number(thumbnail.frameSeq || 0),
400
+ ThumbnailWidth: Number(thumbnail.width || 0),
401
+ ThumbnailHeight: Number(thumbnail.height || 0),
402
+ ThumbnailMimeType: String(thumbnail.mimeType || thumbnail.format || ''),
403
+ ThumbnailCapturedAt: String(thumbnail.capturedAt || ''),
404
+ ThumbnailReceivedAt: String(thumbnail.receivedAt || ''),
405
+ ThumbnailDataUrl: String(thumbnail.dataUrl || ''),
406
+ LiveStreamActive: liveStream.active === true,
407
+ LiveStreamId: String(liveStream.streamId || ''),
408
+ LiveStreamMode: String(liveStream.mode || ''),
409
+ LiveStreamFps: Number(liveStream.fps || 0),
410
+ LiveStreamStartedAt: String(liveStream.startedAt || ''),
411
+ LiveStreamStoppedAt: String(liveStream.stoppedAt || ''),
412
+ LiveStreamLastFrameAt: String(liveStream.lastFrameAt || ''),
413
+ LiveStreamFrameSeq: Number(liveStream.lastFrameSeq || 0),
414
+ LiveFrameStreamId: String(liveFrame.streamId || ''),
415
+ LiveFrameSeq: Number(liveFrame.frameSeq || 0),
416
+ LiveFrameWidth: Number(liveFrame.width || 0),
417
+ LiveFrameHeight: Number(liveFrame.height || 0),
418
+ LiveFrameMimeType: String(liveFrame.mimeType || liveFrame.format || ''),
419
+ LiveFrameCapturedAt: String(liveFrame.capturedAt || ''),
420
+ LiveFrameReceivedAt: String(liveFrame.receivedAt || ''),
421
+ LiveFrameDataUrl: String(liveFrame.dataUrl || ''),
422
+ LatestTaskId: String(latestTask.taskId || ''),
423
+ LatestTaskCommandId: String(latestTask.commandId || ''),
424
+ LatestTaskTitle: String(latestTask.title || ''),
425
+ LatestTaskInstructionPreview: String(latestTask.instructionPreview || ''),
426
+ LatestTaskStatus: String(latestTask.status || ''),
427
+ LatestTaskApprovalLevel: String(latestTask.approvalLevel || ''),
428
+ LatestTaskUpdatedAt: String(latestTask.updatedAt || latestTask.completedAt || latestTask.sentAt || ''),
429
+ LatestTaskError: String(latestTask.error || ''),
430
+ LatestTaskResultModel: String(latestTask.resultModel || ''),
431
+ LatestTaskResultResponseId: String(latestTask.resultResponseId || ''),
432
+ LatestTaskResultSummary: String(latestTask.resultSummary || '')
433
+ };
434
+ }
435
+
436
+ async function loadCss3DManager() {
437
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
438
+ const managerPath = path.resolve(__dirname, '../../MindExecution.Shared/wwwroot/js/mind-map-css3d-manager.js');
439
+ const source = await fs.readFile(managerPath, 'utf8');
440
+ const document = new MiniDocument();
441
+ const objectUrlCalls = [];
442
+ const revokedObjectUrls = [];
443
+ const imageBitmapCalls = [];
444
+ const fetchCalls = [];
445
+ const runtimeTrace = [];
446
+ const webSocketConnections = [];
447
+ const webSocketSends = [];
448
+ const textOverlayInvalidations = [];
449
+ class SmokeURL extends URL {}
450
+ SmokeURL.createObjectURL = blob => {
451
+ objectUrlCalls.push(blob);
452
+ return `blob:remote-fleet-smoke-${objectUrlCalls.length}`;
453
+ };
454
+ SmokeURL.revokeObjectURL = value => {
455
+ revokedObjectUrls.push(String(value || ''));
456
+ };
457
+ class MiniWebSocket {
458
+ static CONNECTING = 0;
459
+ static OPEN = 1;
460
+ static CLOSING = 2;
461
+ static CLOSED = 3;
462
+
463
+ constructor(url) {
464
+ this.url = String(url || '');
465
+ this.readyState = MiniWebSocket.CONNECTING;
466
+ this.binaryType = '';
467
+ this.sent = [];
468
+ this.closeCount = 0;
469
+ webSocketConnections.push(this);
470
+ setTimeout(() => {
471
+ if (this.readyState !== MiniWebSocket.CONNECTING) return;
472
+ this.readyState = MiniWebSocket.OPEN;
473
+ this.onopen?.({ type: 'open' });
474
+ }, 0);
475
+ }
476
+
477
+ send(payload) {
478
+ const text = typeof payload === 'string' ? payload : String(payload || '');
479
+ this.sent.push(text);
480
+ webSocketSends.push({ url: this.url, payload: text });
481
+ }
482
+
483
+ close() {
484
+ if (this.readyState === MiniWebSocket.CLOSED) return;
485
+ this.closeCount += 1;
486
+ this.readyState = MiniWebSocket.CLOSED;
487
+ this.onclose?.({ type: 'close' });
488
+ }
489
+ }
490
+ const context = {
491
+ console,
492
+ document,
493
+ location: {
494
+ origin: 'http://localhost:5147'
495
+ },
496
+ navigator: {
497
+ clipboard: {
498
+ writeText: async () => {}
499
+ }
500
+ },
501
+ setInterval: () => 0,
502
+ clearInterval: () => {},
503
+ setTimeout,
504
+ clearTimeout,
505
+ Date,
506
+ Math,
507
+ Number,
508
+ String,
509
+ Boolean,
510
+ Array,
511
+ Object,
512
+ JSON,
513
+ RegExp,
514
+ Map,
515
+ Set,
516
+ WeakMap,
517
+ Blob,
518
+ TextDecoder,
519
+ TextEncoder,
520
+ requestAnimationFrame: callback => setTimeout(() => callback(Date.now()), 0),
521
+ cancelAnimationFrame: id => clearTimeout(id),
522
+ createImageBitmap: async blob => {
523
+ imageBitmapCalls.push(blob);
524
+ return {
525
+ width: 64,
526
+ height: 36,
527
+ close() {
528
+ this.closed = true;
529
+ }
530
+ };
531
+ },
532
+ THREE: createThreeStub(),
533
+ URL: SmokeURL,
534
+ WebSocket: MiniWebSocket,
535
+ fetch: async (url, options = {}) => {
536
+ fetchCalls.push({ url: String(url || ''), options });
537
+ return {
538
+ ok: true,
539
+ status: 200,
540
+ json: async () => ({
541
+ bridgeToken: 'render-smoke-bridge-token',
542
+ remoteFrameWsPath: '/api/remote/frames/ws',
543
+ remoteInputWsPath: '/api/remote/input/ws'
544
+ })
545
+ };
546
+ },
547
+ RuntimeTrace: {
548
+ emit(type, data = {}) {
549
+ runtimeTrace.push({ type, ...data });
550
+ }
551
+ },
552
+ MindMapTextOverlayV2: {
553
+ invalidateReadonlySource(module, nodeId, reason) {
554
+ textOverlayInvalidations.push({ module, nodeId, reason });
555
+ return true;
556
+ },
557
+ invalidateNode(module, nodeId, reason) {
558
+ textOverlayInvalidations.push({ module, nodeId, reason, fallback: true });
559
+ }
560
+ },
561
+ Promise
562
+ };
563
+ context.window = context;
564
+ context.self = context;
565
+
566
+ vm.runInNewContext(source, context, { filename: managerPath });
567
+ return {
568
+ manager: context.window.MindMapCss3DManager,
569
+ document,
570
+ diagnostics: {
571
+ objectUrlCalls,
572
+ revokedObjectUrls,
573
+ imageBitmapCalls,
574
+ fetchCalls,
575
+ runtimeTrace,
576
+ webSocketConnections,
577
+ webSocketSends,
578
+ textOverlayInvalidations
579
+ }
580
+ };
581
+ }
582
+
583
+ function wait(ms = 0) {
584
+ return new Promise(resolve => setTimeout(resolve, ms));
585
+ }
586
+
587
+ function encodeRemoteBinaryFrame(metadata, payload = new Uint8Array([0xff, 0xd8, 0xff, 0xd9])) {
588
+ const metaBytes = new TextEncoder().encode(JSON.stringify(metadata));
589
+ const payloadBytes = payload instanceof Uint8Array ? payload : new Uint8Array(payload);
590
+ const buffer = new ArrayBuffer(4 + metaBytes.byteLength + payloadBytes.byteLength);
591
+ const view = new DataView(buffer);
592
+ view.setUint32(0, metaBytes.byteLength);
593
+ const bytes = new Uint8Array(buffer);
594
+ bytes.set(metaBytes, 4);
595
+ bytes.set(payloadBytes, 4 + metaBytes.byteLength);
596
+ return buffer;
597
+ }
598
+
599
+ function buildMonitorNode(devices, hubStatus, latestTaskBatch = null, recentTaskBatches = [], lastError = '', nodeId = 'remote-fleet-render-smoke') {
600
+ const connected = devices.filter(device => device.Connected).length;
601
+ const endpoint = hubStatus.agentEndpoint || '127.0.0.1:5197';
602
+ const pairToken = hubStatus.pairToken || 'render-smoke-token';
603
+ const hostTargetState = hubStatus.hostTargetActive
604
+ ? (hubStatus.hostTargetNodeId === nodeId ? 'hosting' : 'other-monitor')
605
+ : 'inactive';
606
+ return {
607
+ id: nodeId,
608
+ contentType: 'templateLauncher',
609
+ metadata: {
610
+ SemanticType: 'RemoteFleetMonitor',
611
+ RemoteFleetSchemaVersion: 'remote-fleet@1',
612
+ RemoteFleetViewMode: 'all-devices',
613
+ RemoteFleetLastRefreshAtUtc: new Date().toISOString(),
614
+ RemoteFleetHubStatus: 'online',
615
+ RemoteFleetHubEndpoint: endpoint,
616
+ RemoteFleetManagerPackage: hubStatus.managerPackage || 'mindexec-ai',
617
+ RemoteFleetManagerVersion: hubStatus.managerVersion || 'render-smoke-manager',
618
+ RemoteFleetAgentPackage: '@mindexec/remote',
619
+ RemoteFleetPairTokenPreview: '<pair-token>',
620
+ RemoteFleetConnectCommand: `npx @mindexec/remote connect --manager ${endpoint} --pair ${pairToken}`,
621
+ RemoteFleetDeviceCount: String(devices.length),
622
+ RemoteFleetConnectedDeviceCount: String(connected),
623
+ RemoteFleetCanvasPagination: 'none',
624
+ RemoteFleetHostTargetState: hostTargetState,
625
+ RemoteFleetHostTargetNodeId: hubStatus.hostTargetNodeId || '',
626
+ RemoteFleetHostTargetLeaseId: hubStatus.hostTargetLeaseId || '',
627
+ RemoteFleetHostTargetEndpoint: hubStatus.hostTargetEndpoint || endpoint,
628
+ RemoteFleetHostTargetActivatedAtUtc: hubStatus.hostTargetActivatedAt || '',
629
+ RemoteFleetHostTargetUpdatedAtUtc: hubStatus.hostTargetUpdatedAt || '',
630
+ RemoteFleetHostTargetExpiresAtUtc: hubStatus.hostTargetExpiresAt || '',
631
+ RemoteFleetDevicesJson: JSON.stringify(devices),
632
+ RemoteFleetLatestTaskBatchJson: latestTaskBatch ? JSON.stringify(latestTaskBatch) : '',
633
+ RemoteFleetRecentTaskBatchesJson: JSON.stringify(recentTaskBatches),
634
+ RemoteFleetLastError: String(lastError || '')
635
+ }
636
+ };
637
+ }
638
+
639
+ function createRemoteFleetTemplateShell(document, focusDeviceId = '', nodeId = 'remote-fleet-render-smoke') {
640
+ const nodeShell = document.createElement('div');
641
+ nodeShell.setAttribute('class', 'map-node-template-card map-node-remote-fleet');
642
+ nodeShell.dataset.nodeId = nodeId;
643
+ const shell = document.createElement('div');
644
+ shell.setAttribute('class', 'template-card__shell template-card__shell--remote-fleet');
645
+ const header = document.createElement('div');
646
+ header.setAttribute('class', 'template-card__header template-card__header--remote-fleet');
647
+ const icon = document.createElement('div');
648
+ icon.setAttribute('class', 'template-card__icon template-card__icon--remote-fleet');
649
+ const titleWrap = document.createElement('div');
650
+ titleWrap.setAttribute('class', 'template-card__title-block');
651
+ titleWrap.textContent = 'Multi Desktop Monitor';
652
+ header.appendChild(icon);
653
+ header.appendChild(titleWrap);
654
+ const bodyView = document.createElement('div');
655
+ bodyView.setAttribute('class', 'template-card__remote-fleet-body map-node-remote-fleet__body');
656
+ bodyView.dataset.nodeId = nodeId;
657
+ bodyView.dataset.remoteFleetAutoMonitor = 'false';
658
+ if (focusDeviceId) {
659
+ bodyView.dataset.remoteFleetFocusDeviceId = focusDeviceId;
660
+ }
661
+ shell.appendChild(header);
662
+ shell.appendChild(bodyView);
663
+ nodeShell.appendChild(shell);
664
+ return { nodeShell, bodyView };
665
+ }
666
+
667
+ function buildDeviceNode(device, hubStatus) {
668
+ const endpoint = hubStatus.agentEndpoint || '127.0.0.1:5197';
669
+ return {
670
+ id: 'remote-device-render-smoke',
671
+ contentType: 'memo',
672
+ metadata: {
673
+ SemanticType: 'RemoteFleetDevice',
674
+ RemoteFleetSchemaVersion: 'remote-device@1',
675
+ RemoteFleetViewMode: 'pinned-device',
676
+ RemoteFleetLastRefreshAtUtc: new Date().toISOString(),
677
+ RemoteFleetHubStatus: 'online',
678
+ RemoteFleetHubEndpoint: endpoint,
679
+ RemoteFleetManagerPackage: hubStatus.managerPackage || 'mindexec-ai',
680
+ RemoteFleetManagerVersion: hubStatus.managerVersion || 'render-smoke-manager',
681
+ RemoteFleetAgentPackage: '@mindexec/remote',
682
+ RemoteFleetPinnedDeviceId: device.DeviceId,
683
+ RemoteFleetPinnedDeviceJson: JSON.stringify(device),
684
+ RemoteFleetLastError: ''
685
+ }
686
+ };
687
+ }
688
+
689
+ function createThreeStub() {
690
+ class Vector3 {
691
+ constructor(x = 0, y = 0, z = 0) {
692
+ this.x = x;
693
+ this.y = y;
694
+ this.z = z;
695
+ }
696
+
697
+ set(x = 0, y = 0, z = 0) {
698
+ this.x = x;
699
+ this.y = y;
700
+ this.z = z;
701
+ return this;
702
+ }
703
+ }
704
+
705
+ class Matrix4 {
706
+ multiplyMatrices() { return this; }
707
+ }
708
+
709
+ class Frustum {
710
+ setFromProjectionMatrix() { return this; }
711
+ intersectsBox() { return true; }
712
+ }
713
+
714
+ class Quaternion {}
715
+
716
+ class Box3 {
717
+ setFromCenterAndSize() { return this; }
718
+ }
719
+
720
+ return { Box3, Frustum, Matrix4, Quaternion, Vector3 };
721
+ }
722
+
723
+ const hub = createRemoteHub({
724
+ managerPackage: 'mindexec-ai',
725
+ managerVersion: 'render-smoke-manager',
726
+ env: {
727
+ MINDEXEC_REMOTE_HUB: '1',
728
+ REMOTE_HUB_HOST: '127.0.0.1',
729
+ REMOTE_HUB_PORT: '0',
730
+ REMOTE_HUB_PAIR_TOKEN: 'render-smoke-token'
731
+ }
732
+ });
733
+
734
+ try {
735
+ await hub.start();
736
+ const seeded = hub.seedSyntheticFleet({
737
+ count: SYNTHETIC_COUNT,
738
+ connectedRatio: 0.84,
739
+ thumbnailRatio: 0.72,
740
+ aiAssistRatio: 0.42,
741
+ liveCount: 0
742
+ });
743
+ assert.equal(seeded.ok, true);
744
+ assert.equal(seeded.seeded, SYNTHETIC_COUNT);
745
+
746
+ const seededAiTarget = hub.listDevices().find(device =>
747
+ device.connected && device.capabilities?.taskDispatch && device.capabilities?.aiAssist);
748
+ assert.ok(seededAiTarget);
749
+ const renderAiTask = hub.requestAgentTask(seededAiTarget.deviceId, {
750
+ instruction: 'Synthetic render smoke AI task: report model metadata to the canvas.',
751
+ title: 'Render smoke AI task',
752
+ approvalLevel: 'ai-assist',
753
+ model: 'synthetic-render-ai'
754
+ });
755
+ assert.equal(renderAiTask.ok, true);
756
+
757
+ const seededLiveTarget = hub.listDevices().find(device =>
758
+ device.connected && device.capabilities?.liveStream);
759
+ assert.ok(seededLiveTarget);
760
+ const renderLive = hub.startLiveStream(seededLiveTarget.deviceId, {
761
+ streamId: 'render-smoke-live',
762
+ fps: 20,
763
+ maxWidth: 960,
764
+ maxHeight: 540,
765
+ quality: 60
766
+ });
767
+ assert.equal(renderLive.ok, true);
768
+
769
+ const rawDevices = hub.listDevices();
770
+ const devices = rawDevices.map(projectDevice);
771
+ const connectedCount = devices.filter(device => device.Connected).length;
772
+ const aiCount = devices.filter(device => device.Connected && device.AiAssistEnabled).length;
773
+ const focusedDevice = devices.find(device => device.Connected && device.LiveStreamActive)
774
+ || devices.find(device => device.Connected);
775
+ assert.ok(focusedDevice);
776
+ focusedDevice.LatestTaskId = 'render-smoke-timeout-task';
777
+ focusedDevice.LatestTaskCommandId = 'render-smoke-timeout-command';
778
+ focusedDevice.LatestTaskTitle = 'Timed out smoke task';
779
+ focusedDevice.LatestTaskInstructionPreview = 'This synthetic task timed out before the agent replied.';
780
+ focusedDevice.LatestTaskStatus = 'failed';
781
+ focusedDevice.LatestTaskApprovalLevel = 'task-only';
782
+ focusedDevice.LatestTaskUpdatedAt = new Date().toISOString();
783
+ focusedDevice.LatestTaskError = 'task-timeout';
784
+ focusedDevice.LatestTaskResultSummary = '';
785
+ const aiResultDevice = devices.find(device =>
786
+ device.DeviceId !== focusedDevice.DeviceId
787
+ && device.Connected);
788
+ assert.ok(aiResultDevice);
789
+ aiResultDevice.LatestTaskId = 'render-smoke-overview-ai-task';
790
+ aiResultDevice.LatestTaskCommandId = 'render-smoke-overview-ai-command';
791
+ aiResultDevice.LatestTaskTitle = 'Overview AI result';
792
+ aiResultDevice.LatestTaskStatus = 'completed';
793
+ aiResultDevice.LatestTaskApprovalLevel = 'ai-assist';
794
+ aiResultDevice.LatestTaskUpdatedAt = new Date(Date.now() - 1000).toISOString();
795
+ aiResultDevice.LatestTaskError = '';
796
+ aiResultDevice.LatestTaskResultModel = 'synthetic-render-ai';
797
+ aiResultDevice.LatestTaskResultResponseId = 'synthetic-response-overview';
798
+ aiResultDevice.LatestTaskResultSummary = 'Overview AI result visible in the fleet monitor.';
799
+ const latestTaskBatch = {
800
+ batchId: 'render-smoke-batch',
801
+ title: 'Render smoke batch',
802
+ instructionPreview: 'Render smoke batch instruction preview.',
803
+ approvalLevel: 'ai-assist',
804
+ status: 'running',
805
+ requestedAt: new Date(Date.now() - 2500).toISOString(),
806
+ updatedAt: new Date().toISOString(),
807
+ total: 210,
808
+ queued: 210,
809
+ pending: 1,
810
+ completed: 208,
811
+ failed: 1,
812
+ timedOut: 1,
813
+ results: []
814
+ };
815
+ const recentTaskBatches = [
816
+ latestTaskBatch,
817
+ {
818
+ batchId: 'render-smoke-previous-ai-batch',
819
+ title: 'Previous AI batch',
820
+ instructionPreview: 'Previous AI batch instruction preview.',
821
+ approvalLevel: 'ai-assist',
822
+ status: 'completed',
823
+ requestedAt: new Date(Date.now() - 180000).toISOString(),
824
+ updatedAt: new Date(Date.now() - 150000).toISOString(),
825
+ total: 42,
826
+ queued: 42,
827
+ pending: 0,
828
+ completed: 42,
829
+ failed: 0,
830
+ timedOut: 0,
831
+ results: []
832
+ }
833
+ ];
834
+
835
+ const { manager, document, diagnostics } = await loadCss3DManager();
836
+ assert.equal(typeof manager?.renderRemoteFleetMonitorForTest, 'function');
837
+ assert.equal(typeof manager?.renderRemoteFleetDeviceForTest, 'function');
838
+ assert.equal(typeof manager?.applyRemoteFleetFramePatchesForTest, 'function');
839
+ assert.equal(typeof manager?.setModuleForTest, 'function');
840
+
841
+ const dotNetCalls = [];
842
+ const dotNetHelper = {
843
+ invokeMethodAsync: async (methodName, ...args) => {
844
+ dotNetCalls.push({ methodName, args });
845
+ if (methodName === 'DispatchRemoteFleetTaskBatchFromJs') {
846
+ const targetIds = Array.isArray(args[1]) ? args[1] : [];
847
+ const failedDeviceId = targetIds[targetIds.length - 1] || 'synthetic-pc-failed';
848
+ return {
849
+ success: true,
850
+ total: targetIds.length,
851
+ queued: Math.max(0, targetIds.length - 1),
852
+ failed: 1,
853
+ failedDeviceIds: [failedDeviceId],
854
+ failurePreview: `${failedDeviceId}: device-ai-assist-unavailable`
855
+ };
856
+ }
857
+
858
+ if (methodName === 'DispatchRemoteFleetTaskFromJs') {
859
+ const useAiAssist = args[3] === true;
860
+ const total = useAiAssist ? aiCount : connectedCount;
861
+ return {
862
+ success: true,
863
+ total,
864
+ queued: total,
865
+ failed: 0,
866
+ approvalLevel: useAiAssist ? 'ai-assist' : 'task-only'
867
+ };
868
+ }
869
+
870
+ if (methodName === 'SetRemoteFleetHostFromJs') {
871
+ return {
872
+ success: true,
873
+ active: args[1] === true,
874
+ registryStatus: args[1] === true ? 'local' : 'inactive',
875
+ registryReason: args[1] === true ? 'registry-render-smoke' : 'inactive'
876
+ };
877
+ }
878
+
879
+ if (methodName === 'AddRemoteFleetDeviceNodeFromJs') {
880
+ const deviceId = String(args[1] || '');
881
+ return {
882
+ success: true,
883
+ nodeId: 'remote-device-render-smoke',
884
+ deviceId,
885
+ nodeState: buildDeviceNode(
886
+ devices.find(device => device.DeviceId === deviceId) || focusedDevice,
887
+ hub.getStatus())
888
+ };
889
+ }
890
+
891
+ return { success: true };
892
+ }
893
+ };
894
+ const moduleRef = {
895
+ dotNetHelper,
896
+ nodeObjectsById: new Map(),
897
+ _visibleIds: new Set(['remote-fleet-render-smoke']),
898
+ _prevVisibleIds: new Set(['remote-fleet-render-smoke']),
899
+ _forceUpdateFrames: 0,
900
+ _textOverlayV2State: {
901
+ cards: new Map(),
902
+ passiveCandidateIds: new Set(['remote-fleet-render-smoke']),
903
+ layer: document.createElement('div')
904
+ },
905
+ requestAnimationWake(reason) {
906
+ this._lastAnimationWakeReason = reason;
907
+ this._animationWakeCount = Number(this._animationWakeCount || 0) + 1;
908
+ },
909
+ isAnimationLoopActive() {
910
+ return true;
911
+ }
912
+ };
913
+ manager.setModuleForTest(moduleRef);
914
+
915
+ const { nodeShell, bodyView } = createRemoteFleetTemplateShell(document, focusedDevice.DeviceId);
916
+ document.body.appendChild(nodeShell);
917
+ const monitorNode = buildMonitorNode(devices, hub.getStatus({ includeSecrets: true }), latestTaskBatch, recentTaskBatches);
918
+ moduleRef.nodeObjectsById.set('remote-fleet-render-smoke', {
919
+ model: monitorNode,
920
+ currentType: 'CSS',
921
+ cssObject: {
922
+ visible: true,
923
+ element: nodeShell
924
+ }
925
+ });
926
+ document.body.appendChild(moduleRef._textOverlayV2State.layer);
927
+
928
+ manager.renderRemoteFleetMonitorForTest(bodyView, monitorNode);
929
+ const { nodeShell: mirrorShell, bodyView: mirrorBodyView } = createRemoteFleetTemplateShell(document, focusedDevice.DeviceId);
930
+ document.body.appendChild(mirrorShell);
931
+ mirrorBodyView.dataset.remoteFleetDensity = 'cards';
932
+
933
+ let cards = bodyView.querySelectorAll('article[data-device-id]');
934
+ assert.equal(cards.length, connectedCount);
935
+ assert.equal(bodyView.querySelector('[data-remote-fleet-match-count="true"]'), null);
936
+ assert.equal(bodyView.querySelector('[data-remote-fleet-search="true"]'), null);
937
+ assert.equal(bodyView.querySelectorAll('select').length, 0);
938
+ const deviceGrid = bodyView.querySelector('[data-remote-fleet-device-grid="true"]');
939
+ assert.ok(deviceGrid);
940
+ assert.match(deviceGrid.style.cssText, /padding:\s*0 4px;/);
941
+ const statusFooter = bodyView.querySelector('[data-remote-fleet-status-rail="true"]');
942
+ assert.ok(statusFooter);
943
+ const bodyChildOrder = Array.from(bodyView.children).map(child =>
944
+ Object.keys(child.dataset || {}).join(',') || child.tagName).join('|');
945
+ assert.ok(bodyChildOrder.endsWith('remoteFleetStatusRail'), bodyChildOrder);
946
+ assert.ok(statusFooter.style.cssText.includes('flex-direction: row'));
947
+ assert.ok(statusFooter.style.cssText.includes('justify-content: flex-end'));
948
+ const sizeControls = statusFooter.querySelector('[data-remote-fleet-size-controls="true"]');
949
+ assert.ok(sizeControls);
950
+ assert.equal(sizeControls.querySelector('[data-remote-fleet-action="monitor-size-down"]')?.textContent, '-');
951
+ assert.equal(sizeControls.querySelector('[data-remote-fleet-action="monitor-size-up"]')?.textContent, '+');
952
+ assert.match(statusFooter.style.cssText, /box-sizing:\s*border-box;/);
953
+ assert.equal(statusFooter.querySelectorAll('[data-remote-fleet-status-item]').length, 5);
954
+ assert.ok(statusFooter.querySelector('[data-remote-fleet-status-item="route"]'));
955
+ const initialDetailPanel = bodyView.querySelector('[data-remote-fleet-detail-panel="true"]');
956
+ assert.equal(initialDetailPanel, null);
957
+ const initialSelectedCard = bodyView.querySelector(`article[data-device-id="${focusedDevice.DeviceId}"]`);
958
+ assert.ok(initialSelectedCard);
959
+ assert.equal(initialSelectedCard?.querySelector('[data-remote-fleet-selected-indicator="true"]'), null);
960
+ assert.equal(bodyView.querySelectorAll('[data-remote-fleet-action="pin-device"]').length, 0);
961
+ assert.equal(bodyView.querySelectorAll('[data-remote-fleet-action="task-device"]').length, 0);
962
+ assert.equal(bodyView.querySelectorAll('[data-remote-fleet-action="thumbnail-device"]').length, 0);
963
+ assert.equal(bodyView.querySelectorAll('[data-remote-fleet-frame-badge="true"]').length, 0);
964
+ const firstPreview = cards[0]?.querySelector('[data-remote-fleet-device-preview="tile"]');
965
+ assert.ok(firstPreview);
966
+ assert.match(cards[0]?.style.cssText || '', /border-radius:\s*0/);
967
+ assert.match(firstPreview.style.cssText, /border-radius:\s*0/);
968
+ assert.match(cards[0]?.title || '', /Status:\s*(Connected|Offline)/);
969
+ assert.match(cards[0]?.title || '', /Seen:/);
970
+ assert.match(cards[0]?.title || '', /Uptime:/);
971
+ assert.equal(/\b(Seen|Uptime|Mem|Load)\b/.test(cards[0]?.textContent || ''), false);
972
+ assert.match(deviceGrid.style.cssText, /minmax\(198px,\s*1fr\)/);
973
+ sizeControls.querySelector('[data-remote-fleet-action="monitor-size-up"]').dispatchEvent({ type: 'click' });
974
+ assert.equal(bodyView.dataset.remoteFleetDensity, 'large');
975
+ assert.match(bodyView.querySelector('[data-remote-fleet-device-grid="true"]')?.style.cssText || '', /minmax\(297px,\s*1fr\)/);
976
+ assert.equal(mirrorBodyView.dataset.remoteFleetDensity, 'large');
977
+ assert.match(mirrorBodyView.querySelector('[data-remote-fleet-device-grid="true"]')?.style.cssText || '', /minmax\(297px,\s*1fr\)/);
978
+ assert.ok(diagnostics.runtimeTrace.some(entry =>
979
+ entry.type === 'remote.monitor.sizeChanged'
980
+ && entry.nodeId === 'remote-fleet-render-smoke'
981
+ && entry.density === 'large'
982
+ && entry.css3dOnly === true));
983
+ bodyView.querySelector('[data-remote-fleet-action="monitor-size-down"]').dispatchEvent({ type: 'click' });
984
+ assert.equal(bodyView.dataset.remoteFleetDensity, 'cards');
985
+ assert.match(bodyView.querySelector('[data-remote-fleet-device-grid="true"]')?.style.cssText || '', /minmax\(198px,\s*1fr\)/);
986
+ assert.equal(mirrorBodyView.dataset.remoteFleetDensity, 'cards');
987
+ assert.match(mirrorBodyView.querySelector('[data-remote-fleet-device-grid="true"]')?.style.cssText || '', /minmax\(198px,\s*1fr\)/);
988
+ bodyView.querySelector('[data-remote-fleet-action="monitor-size-down"]').dispatchEvent({ type: 'click' });
989
+ assert.equal(bodyView.dataset.remoteFleetDensity, 'dense');
990
+ assert.match(bodyView.querySelector('[data-remote-fleet-device-grid="true"]')?.style.cssText || '', /minmax\(132px,\s*1fr\)/);
991
+ bodyView.querySelector('[data-remote-fleet-action="monitor-size-up"]').dispatchEvent({ type: 'click' });
992
+ assert.equal(bodyView.dataset.remoteFleetDensity, 'cards');
993
+ assert.match(bodyView.querySelector('[data-remote-fleet-device-grid="true"]')?.style.cssText || '', /minmax\(198px,\s*1fr\)/);
994
+ mirrorShell.remove();
995
+ cards = bodyView.querySelectorAll('article[data-device-id]');
996
+ const patchTarget = devices.find(device =>
997
+ device.Connected === true
998
+ && device.ThumbnailEnabled === true);
999
+ assert.ok(patchTarget);
1000
+ const patchCard = Array.from(cards).find(card => card.dataset.deviceId === patchTarget.DeviceId);
1001
+ const patchPreview = patchCard?.querySelector('[data-remote-fleet-device-preview="tile"]');
1002
+ assert.ok(patchPreview);
1003
+ const patchKind = String(patchPreview.dataset.remoteFleetFrameKind || '').toLowerCase() === 'live'
1004
+ ? 'live'
1005
+ : 'thumbnail';
1006
+ const patchUrl = `/api/remote/devices/${encodeURIComponent(patchTarget.DeviceId)}/${patchKind}?token=render-smoke-frame&seq=9999`;
1007
+ const patchCount = manager.applyRemoteFleetFramePatchesForTest(bodyView, [{
1008
+ deviceId: patchTarget.DeviceId,
1009
+ kind: patchKind,
1010
+ frameSeq: 9999,
1011
+ frameUrl: patchUrl,
1012
+ receivedAt: new Date().toISOString()
1013
+ }]);
1014
+ assert.equal(patchCount, 1, JSON.stringify({
1015
+ targetDeviceId: patchTarget.DeviceId,
1016
+ previewCount: bodyView.querySelectorAll('[data-remote-fleet-device-preview]').length,
1017
+ previewIds: Array.from(bodyView.querySelectorAll('[data-remote-fleet-device-preview]')).slice(0, 12).map(preview => preview.dataset.deviceId || ''),
1018
+ currentKind: patchPreview.dataset.remoteFleetFrameKind || '',
1019
+ currentSeq: patchPreview.dataset.remoteFleetFrameSeq || '',
1020
+ currentUrl: patchPreview.dataset.remoteFleetFrameUrl || ''
1021
+ }));
1022
+ await wait();
1023
+ assert.equal(patchPreview.dataset.remoteFleetFrameSeq, '9999');
1024
+ assert.equal(patchPreview.dataset.remoteFleetFrameUrl, patchUrl);
1025
+ assert.equal(patchPreview.dataset.remoteFleetPendingFrameUrl || '', '');
1026
+ assert.ok(patchPreview.querySelector('canvas[data-remote-fleet-frame-canvas="true"]'));
1027
+ assert.equal(patchPreview.querySelector('img[data-remote-fleet-frame-image="true"]')?.dataset.remoteFleetFrameUrl, patchUrl);
1028
+ assert.equal(patchPreview.querySelector('[data-remote-fleet-frame-badge="true"]'), null);
1029
+
1030
+ const objectUrlCountBeforeBinary = diagnostics.objectUrlCalls.length;
1031
+ const imageBitmapCountBeforeBinary = diagnostics.imageBitmapCalls.length;
1032
+ const drawCountBeforeBinary = document.canvasDrawCalls.length;
1033
+ const binaryPatchCount = manager.applyRemoteFleetFramePatchesForTest(bodyView, [{
1034
+ deviceId: patchTarget.DeviceId,
1035
+ kind: 'live',
1036
+ frameSeq: 10000,
1037
+ frameUrl: '',
1038
+ streamId: 'render-smoke-binary-live',
1039
+ contentHash: 'render-smoke-binary-live-10000',
1040
+ receivedAt: new Date().toISOString(),
1041
+ _remoteFleetPayloadBlob: new Blob([new Uint8Array([0xff, 0xd8, 0xff, 0xd9])], { type: 'image/jpeg' }),
1042
+ _remoteFleetBinaryFrame: true
1043
+ }]);
1044
+ assert.equal(binaryPatchCount, 1);
1045
+ await wait(20);
1046
+ const binaryCanvas = patchPreview.querySelector('canvas[data-remote-fleet-frame-canvas="true"]');
1047
+ const binaryImage = patchPreview.querySelector('img[data-remote-fleet-frame-image="true"]');
1048
+ assert.equal(patchPreview.dataset.remoteFleetFrameKind, 'live');
1049
+ assert.equal(patchPreview.dataset.remoteFleetFrameSeq, '10000');
1050
+ assert.equal(binaryCanvas?.dataset.remoteFleetFrameSeq, '10000');
1051
+ assert.equal(binaryCanvas?.style.display, 'block');
1052
+ assert.equal(binaryImage?.style.display, 'none');
1053
+ assert.equal(diagnostics.imageBitmapCalls.length, imageBitmapCountBeforeBinary + 1);
1054
+ assert.equal(diagnostics.objectUrlCalls.length, objectUrlCountBeforeBinary);
1055
+ const binaryDrawCalls = document.canvasDrawCalls.slice(drawCountBeforeBinary);
1056
+ assert.ok(
1057
+ binaryDrawCalls.some(call => call.op === 'drawImage'),
1058
+ 'expected binary Blob frame to draw directly to canvas');
1059
+ assert.equal(
1060
+ binaryDrawCalls.some(call => call.op === 'clearRect' || call.op === 'fillRect'),
1061
+ false,
1062
+ 'binary Blob frame paint must not clear/fill the canvas before drawing');
1063
+ const binaryCanvasBeforeRerender = binaryCanvas;
1064
+
1065
+ const liveOverlayCard = document.createElement('div');
1066
+ liveOverlayCard.dataset.nodeId = 'remote-fleet-render-smoke';
1067
+ liveOverlayCard.dataset.sourceKind = 'live';
1068
+ liveOverlayCard.dataset.liveInteractive = 'true';
1069
+ liveOverlayCard.style.display = 'block';
1070
+ moduleRef._textOverlayV2State.cards.set('selection:remote-fleet-render-smoke', liveOverlayCard);
1071
+ moduleRef._forceUpdateFrames = 0;
1072
+ moduleRef._animationWakeCount = 0;
1073
+ moduleRef._lastAnimationWakeReason = '';
1074
+
1075
+ await wait(20);
1076
+ const liveWs = diagnostics.webSocketConnections[0];
1077
+ assert.ok(liveWs, 'expected MDM render to open the binary frame WebSocket');
1078
+ assert.equal(liveWs.readyState, 1, 'binary frame WebSocket should be open before rerender');
1079
+ const wsCountBeforeRerender = diagnostics.webSocketConnections.length;
1080
+ const wsCloseCountBeforeRerender = liveWs.closeCount;
1081
+ const websocketFrameSeq = 10001;
1082
+ liveWs.onmessage?.({
1083
+ data: new Blob([encodeRemoteBinaryFrame({
1084
+ type: 'remote.frame.binary',
1085
+ deviceId: patchTarget.DeviceId,
1086
+ kind: 'live',
1087
+ frameSeq: websocketFrameSeq,
1088
+ streamId: 'render-smoke-ws-live',
1089
+ contentHash: `render-smoke-ws-live-${websocketFrameSeq}`,
1090
+ mimeType: 'image/jpeg',
1091
+ width: 64,
1092
+ height: 36,
1093
+ capturedAt: new Date().toISOString(),
1094
+ receivedAt: new Date().toISOString()
1095
+ })])
1096
+ });
1097
+ await wait(30);
1098
+ assert.equal(
1099
+ patchPreview.dataset.remoteFleetFrameSeq,
1100
+ String(websocketFrameSeq),
1101
+ JSON.stringify(diagnostics.runtimeTrace.slice(-12)));
1102
+ await wait(10);
1103
+ assert.ok(
1104
+ Number(moduleRef._forceUpdateFrames || 0) >= 2,
1105
+ 'binary live frame commits must wake the passive MDM CSS3D frame loop');
1106
+ assert.equal(moduleRef._lastAnimationWakeReason, 'remote-live-css3d-frame');
1107
+ assert.ok(
1108
+ diagnostics.runtimeTrace.some(event => event.type === 'remote.frame.css3dWake'),
1109
+ 'binary live frame commits must trace the MDM CSS3D wake path');
1110
+
1111
+ manager.renderRemoteFleetMonitorForTest(bodyView, buildMonitorNode(devices, hub.getStatus({ includeSecrets: true }), latestTaskBatch, recentTaskBatches));
1112
+ await wait(30);
1113
+ assert.equal(
1114
+ liveWs.closeCount,
1115
+ wsCloseCountBeforeRerender,
1116
+ 'MDM rerender must not close the active binary frame WebSocket');
1117
+ assert.equal(
1118
+ diagnostics.webSocketConnections.length,
1119
+ wsCountBeforeRerender,
1120
+ 'MDM rerender must reuse the active binary frame WebSocket instead of opening a replacement');
1121
+ const rerenderedPatchPreview = bodyView
1122
+ .querySelector(`article[data-device-id="${patchTarget.DeviceId}"]`)
1123
+ ?.querySelector('[data-remote-fleet-device-preview="tile"]');
1124
+ assert.ok(rerenderedPatchPreview);
1125
+ assert.equal(rerenderedPatchPreview.dataset.remoteFleetFrameSeq, String(websocketFrameSeq));
1126
+ const rerenderedPatchCanvas = rerenderedPatchPreview.querySelector('canvas[data-remote-fleet-frame-canvas="true"]');
1127
+ assert.equal(rerenderedPatchCanvas?.style.display, 'block');
1128
+ assert.equal(
1129
+ rerenderedPatchCanvas,
1130
+ binaryCanvasBeforeRerender,
1131
+ 'MDM rerender should reuse the already-painted canvas instead of flashing a blank replacement');
1132
+
1133
+ const otherBoardNodeId = 'remote-fleet-render-smoke-other-board';
1134
+ const { nodeShell: otherBoardShell, bodyView: otherBoardBodyView } =
1135
+ createRemoteFleetTemplateShell(document, focusedDevice.DeviceId, otherBoardNodeId);
1136
+ document.body.appendChild(otherBoardShell);
1137
+ manager.renderRemoteFleetMonitorForTest(
1138
+ otherBoardBodyView,
1139
+ buildMonitorNode(
1140
+ devices,
1141
+ hub.getStatus({ includeSecrets: true }),
1142
+ latestTaskBatch,
1143
+ recentTaskBatches,
1144
+ '',
1145
+ otherBoardNodeId));
1146
+ await wait(30);
1147
+ const otherBoardPatchPreview = otherBoardBodyView
1148
+ .querySelector(`article[data-device-id="${patchTarget.DeviceId}"]`)
1149
+ ?.querySelector('[data-remote-fleet-device-preview="tile"]');
1150
+ assert.ok(otherBoardPatchPreview);
1151
+ assert.equal(
1152
+ otherBoardPatchPreview.dataset.remoteFleetFrameSeq,
1153
+ String(websocketFrameSeq),
1154
+ 'a different-board MDM should prime from the device-global latest binary frame cache');
1155
+ assert.equal(
1156
+ otherBoardPatchPreview.querySelector('canvas[data-remote-fleet-frame-canvas="true"]')?.style.display,
1157
+ 'block');
1158
+ assert.ok(diagnostics.runtimeTrace.some(event =>
1159
+ (event.type === 'remote.frame.wsCachePrimed' || event.type === 'remote.frame.surfaceCachePrimed')
1160
+ && event.nodeId === otherBoardNodeId));
1161
+ otherBoardShell.remove();
1162
+
1163
+ const controlCard = bodyView.querySelector(`article[data-device-id="${patchTarget.DeviceId}"]`);
1164
+ assert.ok(controlCard);
1165
+ controlCard.dispatchEvent({ type: 'dblclick', button: 0 });
1166
+ await wait(30);
1167
+ assert.equal(document.body.querySelector('[data-remote-fleet-control-popup="true"]'), null);
1168
+ const addControlNodeCall = dotNetCalls.find(call =>
1169
+ call.methodName === 'AddRemoteFleetDeviceNodeFromJs'
1170
+ && call.args[0] === 'remote-fleet-render-smoke'
1171
+ && call.args[1] === patchTarget.DeviceId);
1172
+ assert.ok(addControlNodeCall, 'double-clicking an MDM tile should create a remote-control canvas node');
1173
+
1174
+ const alternateDevice = devices.find(device =>
1175
+ device.Connected === true
1176
+ && device.DeviceId !== focusedDevice.DeviceId);
1177
+ assert.ok(alternateDevice);
1178
+ const alternateCard = Array.from(cards).find(card => card.dataset.deviceId === alternateDevice.DeviceId);
1179
+ assert.ok(alternateCard);
1180
+ alternateCard.dispatchEvent({ type: 'click' });
1181
+ assert.equal(bodyView.dataset.remoteFleetSelectedDeviceId, alternateDevice.DeviceId);
1182
+ assert.equal(bodyView.querySelector('[data-remote-fleet-detail-panel="true"]'), null);
1183
+ const selectedAfterClick = bodyView.querySelector(`article[data-device-id="${alternateDevice.DeviceId}"]`);
1184
+ assert.ok(selectedAfterClick);
1185
+ assert.equal(selectedAfterClick?.querySelector('[data-remote-fleet-selected-indicator="true"]'), null);
1186
+ const livePanel = bodyView.querySelector('[data-remote-fleet-live-panel="true"]');
1187
+ assert.equal(livePanel, null);
1188
+ assert.equal(bodyView.querySelector('[data-remote-fleet-action="task-visible"]'), null);
1189
+ assert.equal(bodyView.querySelector('[data-remote-fleet-action="task-connected"]'), null);
1190
+ assert.equal(bodyView.querySelector('[data-remote-fleet-task-input="true"]'), null);
1191
+ assert.equal(bodyView.querySelector('[data-remote-fleet-ai-toggle="true"]'), null);
1192
+ assert.equal(bodyView.textContent.includes('all devices, no paging'), false);
1193
+ assert.equal(bodyView.textContent.includes('Host: Inactive'), false);
1194
+ assert.equal(bodyView.textContent.includes('No screen'), false);
1195
+ assert.equal(bodyView.textContent.includes('mindexec-ai'), false);
1196
+ assert.equal(nodeShell.querySelector('[data-remote-fleet-host-indicator="true"]')?.dataset.remoteFleetHostActive, 'false');
1197
+ const { nodeShell: hostMirrorShell, bodyView: hostMirrorBodyView } = createRemoteFleetTemplateShell(document, focusedDevice.DeviceId);
1198
+ document.body.appendChild(hostMirrorShell);
1199
+ manager.renderRemoteFleetMonitorForTest(hostMirrorBodyView, monitorNode);
1200
+ assert.equal(hostMirrorShell.querySelector('[data-remote-fleet-host-indicator="true"]')?.dataset.remoteFleetHostActive, 'false');
1201
+ const initialHostButton = nodeShell.querySelector('[data-remote-fleet-action="set-host"]');
1202
+ assert.equal(initialHostButton?.textContent, 'Set Host');
1203
+ initialHostButton.dispatchEvent({ type: 'click' });
1204
+ await wait();
1205
+ const setHostCall = dotNetCalls.find(call => call.methodName === 'SetRemoteFleetHostFromJs');
1206
+ assert.ok(setHostCall);
1207
+ assert.equal(setHostCall.args[0], 'remote-fleet-render-smoke');
1208
+ assert.equal(setHostCall.args[1], true);
1209
+ const hostFeedback = bodyView.querySelector('[data-remote-fleet-task-feedback="true"]');
1210
+ assert.equal(hostFeedback?.style.display, 'none');
1211
+ assert.equal(hostFeedback?.textContent, '');
1212
+ assert.equal(nodeShell.querySelector('[data-remote-fleet-host-indicator="true"]')?.dataset.remoteFleetHostActive, 'true');
1213
+ assert.equal(hostMirrorShell.querySelector('[data-remote-fleet-host-indicator="true"]')?.dataset.remoteFleetHostActive, 'true');
1214
+ assert.ok(diagnostics.runtimeTrace.some(entry =>
1215
+ entry.type === 'remote.monitor.projectionInvalidated'
1216
+ && entry.nodeId === 'remote-fleet-render-smoke'
1217
+ && entry.reason === 'host'
1218
+ && entry.css3dOnly === true));
1219
+ hostMirrorShell.remove();
1220
+
1221
+ hub.setHostTarget({
1222
+ nodeId: 'remote-fleet-render-smoke',
1223
+ enabled: true,
1224
+ leaseMs: 30000
1225
+ });
1226
+ manager.renderRemoteFleetMonitorForTest(bodyView, buildMonitorNode(devices, hub.getStatus({ includeSecrets: true }), latestTaskBatch, recentTaskBatches));
1227
+ assert.equal(bodyView.textContent.includes('Host: Active'), false);
1228
+ assert.equal(nodeShell.querySelector('[data-remote-fleet-host-indicator="true"]')?.dataset.remoteFleetHostActive, 'true');
1229
+ assert.equal(nodeShell.querySelector('[data-remote-fleet-action="set-host"]')?.textContent, 'Set Host');
1230
+ assert.equal(nodeShell.querySelector('[data-remote-fleet-action="stop-host"]'), null);
1231
+ hub.setHostTarget({
1232
+ nodeId: 'remote-fleet-render-smoke',
1233
+ enabled: false
1234
+ });
1235
+
1236
+ assert.equal(bodyView.querySelector('[data-remote-fleet-live-panel="true"]'), null);
1237
+ assert.equal(bodyView.querySelector('code'), null);
1238
+ assert.equal(bodyView.textContent.includes('npx @mindexec/remote connect'), false);
1239
+ assert.equal(bodyView.querySelector('[data-remote-fleet-action="copy-command"]'), null);
1240
+ assert.equal(bodyView.querySelector('[data-remote-fleet-action="refresh"]'), null);
1241
+ assert.equal(bodyView.querySelector('[data-remote-fleet-auto-toggle="true"]'), null);
1242
+ assert.equal(bodyView.textContent.includes('synthetic-render-ai'), false);
1243
+ assert.equal(bodyView.textContent.includes('Task timed out waiting for the agent response.'), false);
1244
+ const batchSummary = bodyView.querySelector('[data-remote-fleet-task-batch="true"]');
1245
+ assert.equal(batchSummary, null);
1246
+ const batchHistory = bodyView.querySelector('[data-remote-fleet-task-history="true"]');
1247
+ assert.equal(batchHistory, null);
1248
+ const resultPanel = bodyView.querySelector('[data-remote-fleet-task-results="true"]');
1249
+ assert.equal(resultPanel, null);
1250
+ assert.ok(devices.some(device => /^synthetic-response-/.test(device.LatestTaskResultResponseId)));
1251
+ await wait(20);
1252
+ const liveStartCalls = dotNetCalls
1253
+ .filter(call => call.methodName === 'StartRemoteFleetLiveStreamFromJs');
1254
+ const subscribeMessages = diagnostics.webSocketSends
1255
+ .map(send => {
1256
+ try {
1257
+ return JSON.parse(send.payload);
1258
+ } catch {
1259
+ return null;
1260
+ }
1261
+ })
1262
+ .filter(Boolean);
1263
+ const autoLiveSubscribe = subscribeMessages.find(message =>
1264
+ message.type === 'subscribe'
1265
+ && message.nodeId === 'remote-fleet-render-smoke'
1266
+ && message.autoStartLive === true);
1267
+ assert.ok(diagnostics.fetchCalls.some(call => call.url.includes('/api/status?remoteFrames=ws')));
1268
+ assert.ok(diagnostics.webSocketConnections.length >= 1, 'expected MDM render to open binary frame WebSocket');
1269
+ assert.ok(autoLiveSubscribe, 'expected MDM render to subscribe with autoStartLive over WebSocket');
1270
+ assert.equal(autoLiveSubscribe.fps, 12);
1271
+ assert.equal(autoLiveSubscribe.maxWidth, 960);
1272
+ assert.equal(autoLiveSubscribe.maxHeight, 540);
1273
+ assert.equal(autoLiveSubscribe.quality, 60);
1274
+ assert.ok(autoLiveSubscribe.deviceIds.length > 1, 'expected visible connected devices in WS subscription');
1275
+ assert.ok(diagnostics.runtimeTrace.some(event => event.type === 'remote.live.wsAutoStartRequested'));
1276
+ assert.equal(liveStartCalls.length, 0, 'WebSocket live path must not call DotNet live-start fallback');
1277
+ await wait(320);
1278
+ assert.ok(dotNetCalls.some(call => call.methodName === 'RefreshRemoteFleetMonitorNodeFromJs'));
1279
+ assert.equal(bodyView.dataset.remoteFleetTaskFollowKey, 'render-smoke-batch');
1280
+ assert.ok(Number(bodyView.dataset.remoteFleetTaskFollowTicks || '0') >= 1);
1281
+
1282
+ const feedback = bodyView.querySelector('[data-remote-fleet-task-feedback="true"]');
1283
+ assert.ok(feedback);
1284
+
1285
+ assert.equal(bodyView.querySelector('[data-remote-fleet-ai-toggle="true"]'), null);
1286
+ assert.equal(dotNetCalls.some(call =>
1287
+ call.methodName === 'DispatchRemoteFleetTaskBatchFromJs'
1288
+ || call.methodName === 'DispatchRemoteFleetTaskFromJs'), false);
1289
+
1290
+ const { nodeShell: emptyShell, bodyView: emptyBody } = createRemoteFleetTemplateShell(document);
1291
+ document.body.appendChild(emptyShell);
1292
+ manager.renderRemoteFleetMonitorForTest(emptyBody, buildMonitorNode([], hub.getStatus({ includeSecrets: true })));
1293
+ const emptyScreenShell = emptyBody.querySelector('[data-remote-fleet-empty-screens="true"]');
1294
+ assert.ok(emptyScreenShell);
1295
+ assert.match(emptyScreenShell.style.cssText, /padding:\s*2px 4px 6px 4px;/);
1296
+ const emptyScreens = emptyBody.querySelectorAll('[data-remote-fleet-empty-screen="true"]');
1297
+ assert.ok(emptyScreens.length >= 12, `expected empty monitor to fill space, got ${emptyScreens.length}`);
1298
+ assert.notEqual(emptyScreens.length, 6);
1299
+ assert.match(emptyScreens[0].style.cssText, /border-radius:\s*0/);
1300
+ assert.ok(Array.from(emptyBody.children).map(child =>
1301
+ Object.keys(child.dataset || {}).join(',') || child.tagName).join('|').endsWith('remoteFleetStatusRail'));
1302
+ assert.equal(emptyBody.textContent.includes('No devices connected yet.'), false);
1303
+ assert.equal(emptyBody.textContent.includes('Select a screen'), false);
1304
+ assert.equal(emptyBody.textContent.includes('No screen'), false);
1305
+ assert.equal(emptyBody.textContent.includes('Endpoint 127.0.0.1'), false);
1306
+
1307
+ const oneDevice = devices.find(device => device.Connected === true);
1308
+ assert.ok(oneDevice);
1309
+ const { nodeShell: oneShell, bodyView: oneBody } = createRemoteFleetTemplateShell(document);
1310
+ document.body.appendChild(oneShell);
1311
+ manager.renderRemoteFleetMonitorForTest(oneBody, buildMonitorNode([oneDevice], hub.getStatus({ includeSecrets: true })));
1312
+ const oneCards = oneBody.querySelectorAll('article[data-device-id]');
1313
+ assert.equal(oneCards.length, 1);
1314
+ const onePreview = oneCards[0]?.querySelector('[data-remote-fleet-device-preview="tile"]');
1315
+ assert.ok(onePreview);
1316
+ assert.match(oneCards[0]?.style.cssText || '', /border-radius:\s*0/);
1317
+ assert.match(onePreview.style.cssText, /border-radius:\s*0/);
1318
+ assert.match(oneCards[0]?.title || '', /Status:\s*Connected/);
1319
+ assert.match(oneCards[0]?.title || '', /Seen:/);
1320
+ assert.match(oneCards[0]?.title || '', /Uptime:/);
1321
+ const oneFillers = oneBody.querySelectorAll('[data-remote-fleet-empty-screen="true"]');
1322
+ assert.ok(oneFillers.length > 0, 'single connected monitor wall should keep blank screen placeholders');
1323
+ assert.match(oneFillers[0].style.cssText, /border-radius:\s*0/);
1324
+
1325
+ const { nodeShell: errorShell, bodyView: errorBody } = createRemoteFleetTemplateShell(document);
1326
+ document.body.appendChild(errorShell);
1327
+ manager.renderRemoteFleetMonitorForTest(errorBody, buildMonitorNode([], hub.getStatus({ includeSecrets: true }), null, [], 'RemoteHub is unavailable. Start LocalBridge and retry.'));
1328
+ const errorFooter = errorBody.querySelector('[data-remote-fleet-status-rail="true"]');
1329
+ const footerError = errorFooter?.querySelector('[data-remote-fleet-status-error="true"]');
1330
+ assert.ok(errorFooter);
1331
+ assert.ok(footerError);
1332
+ assert.ok(Array.from(errorBody.children).map(child =>
1333
+ Object.keys(child.dataset || {}).join(',') || child.tagName).join('|').endsWith('remoteFleetStatusRail'));
1334
+ assert.equal(footerError.textContent.includes('RemoteHub is unavailable'), true);
1335
+ assert.equal(Array.from(errorBody.children).some(child =>
1336
+ child !== errorFooter && (child.textContent || '').includes('RemoteHub is unavailable')), false);
1337
+
1338
+ const deviceBody = document.createElement('div');
1339
+ deviceBody.dataset.nodeId = 'remote-device-render-smoke';
1340
+ document.body.appendChild(deviceBody);
1341
+ const sendCountBeforeControlNode = diagnostics.webSocketSends.length;
1342
+ const drawCountBeforeControlNode = document.canvasDrawCalls.length;
1343
+ manager.renderRemoteFleetDeviceForTest(deviceBody, buildDeviceNode(focusedDevice, hub.getStatus()));
1344
+ assert.ok(deviceBody.textContent.includes(focusedDevice.Name));
1345
+ assert.ok(deviceBody.querySelector('[data-remote-fleet-device-toolbar="true"]'));
1346
+ assert.ok(deviceBody.querySelector('[data-remote-fleet-device-actions="true"]'));
1347
+ assert.ok(deviceBody.querySelector('[data-remote-fleet-device-task-panel="true"]'));
1348
+ const deviceStatusBar = deviceBody.querySelector('[data-remote-fleet-device-status-bar="true"]')
1349
+ || deviceBody.querySelector('[data-remote-fleet-device-statusbar="true"]');
1350
+ assert.ok(deviceStatusBar);
1351
+ const deviceControlStage = deviceBody.querySelector('[data-remote-fleet-control-node-stage="true"]');
1352
+ const deviceControlCanvas = deviceBody.querySelector('[data-remote-fleet-control-node-canvas="true"]');
1353
+ assert.ok(deviceControlStage);
1354
+ assert.ok(deviceControlCanvas);
1355
+ assert.equal(
1356
+ deviceControlStage.parentElement,
1357
+ deviceBody,
1358
+ 'RemoteFleetDevice should spend its main body area on the control screen');
1359
+ assert.equal(deviceBody.querySelectorAll('[data-remote-fleet-status-card], [data-remote-fleet-stat]').length, 0);
1360
+ assert.equal(document.activeElement, deviceControlStage);
1361
+ await wait(30);
1362
+ const deviceControlSubscribe = diagnostics.webSocketSends
1363
+ .slice(sendCountBeforeControlNode)
1364
+ .map(send => {
1365
+ try {
1366
+ return JSON.parse(send.payload);
1367
+ } catch {
1368
+ return null;
1369
+ }
1370
+ })
1371
+ .find(message =>
1372
+ message
1373
+ && message.type === 'subscribe'
1374
+ && message.nodeId === 'remote-device-render-smoke'
1375
+ && message.autoStartLive === true
1376
+ && message.fps === 20
1377
+ && Array.isArray(message.deviceIds)
1378
+ && message.deviceIds.includes(focusedDevice.DeviceId));
1379
+ assert.ok(deviceControlSubscribe, 'RemoteFleetDevice node should subscribe to 20fps binary frames');
1380
+ const deviceControlWs = diagnostics.webSocketConnections
1381
+ .filter(ws => ws.url.includes('/api/remote/frames/ws'))
1382
+ .at(-1);
1383
+ assert.ok(deviceControlWs, 'RemoteFleetDevice node should open a binary frame WebSocket');
1384
+ const controlNodeFrameSeq = 30001;
1385
+ deviceControlWs.onmessage?.({
1386
+ data: new Blob([encodeRemoteBinaryFrame({
1387
+ type: 'remote.frame.binary',
1388
+ deviceId: focusedDevice.DeviceId,
1389
+ kind: 'live',
1390
+ frameSeq: controlNodeFrameSeq,
1391
+ streamId: 'render-smoke-control-node-live',
1392
+ contentHash: `render-smoke-control-node-live-${controlNodeFrameSeq}`,
1393
+ mimeType: 'image/jpeg',
1394
+ width: 64,
1395
+ height: 36,
1396
+ capturedAt: new Date().toISOString(),
1397
+ receivedAt: new Date().toISOString()
1398
+ })])
1399
+ });
1400
+ await wait(40);
1401
+ assert.ok(
1402
+ document.canvasDrawCalls
1403
+ .slice(drawCountBeforeControlNode)
1404
+ .some(call => call.canvas === deviceControlCanvas && call.op === 'drawImage'),
1405
+ 'RemoteFleetDevice node should paint binary WebSocket frames directly to its canvas');
1406
+ deviceControlStage.dispatchEvent({
1407
+ type: 'pointerdown',
1408
+ button: 0,
1409
+ pointerId: 11,
1410
+ clientX: 160,
1411
+ clientY: 90
1412
+ });
1413
+ deviceControlStage.dispatchEvent({
1414
+ type: 'pointerup',
1415
+ button: 0,
1416
+ pointerId: 11,
1417
+ clientX: 160,
1418
+ clientY: 90
1419
+ });
1420
+ deviceControlStage.dispatchEvent({
1421
+ type: 'keydown',
1422
+ key: 'A',
1423
+ code: 'KeyA',
1424
+ repeat: false
1425
+ });
1426
+ deviceControlStage.dispatchEvent({
1427
+ type: 'keyup',
1428
+ key: 'A',
1429
+ code: 'KeyA',
1430
+ repeat: false
1431
+ });
1432
+ await wait(50);
1433
+ const inputWsSends = diagnostics.webSocketSends
1434
+ .filter(send => send.url.includes('/api/remote/input/ws'))
1435
+ .map(send => {
1436
+ try {
1437
+ return JSON.parse(send.payload);
1438
+ } catch {
1439
+ return null;
1440
+ }
1441
+ })
1442
+ .filter(Boolean);
1443
+ assert.ok(inputWsSends.length >= 3, 'RemoteFleetDevice node should send pointer and keyboard input over the input WebSocket');
1444
+ const pointerDown = inputWsSends.find(message => message.input?.type === 'pointerDown');
1445
+ const keyDown = inputWsSends.find(message => message.input?.type === 'keyDown');
1446
+ const keyUp = inputWsSends.find(message => message.input?.type === 'keyUp');
1447
+ assert.ok(pointerDown);
1448
+ assert.ok(keyDown);
1449
+ assert.ok(keyUp);
1450
+ assert.equal(pointerDown.nodeId, 'remote-device-render-smoke');
1451
+ assert.equal(pointerDown.deviceId, focusedDevice.DeviceId);
1452
+ assert.equal(pointerDown.input.button, 'left');
1453
+ assert.ok(pointerDown.input.controlLeaseId);
1454
+ assert.ok(pointerDown.input.normalizedX >= 0 && pointerDown.input.normalizedX <= 1);
1455
+ assert.ok(pointerDown.input.normalizedY >= 0 && pointerDown.input.normalizedY <= 1);
1456
+ assert.equal(keyDown.input.key, 'A');
1457
+ assert.equal(keyDown.input.code, 'KeyA');
1458
+ assert.equal(keyUp.input.key, 'A');
1459
+ assert.equal(keyUp.input.code, 'KeyA');
1460
+ assert.equal(
1461
+ dotNetCalls.filter(call => call.methodName === 'SendRemoteFleetInputFromJs').length,
1462
+ 0,
1463
+ 'WebSocket input path should not use the slower DotNet input fallback in the happy path');
1464
+ assert.ok(deviceBody.querySelector('[data-remote-fleet-action="refresh-device"]'));
1465
+ assert.ok(deviceBody.querySelector('[data-remote-fleet-action="task-device"]'));
1466
+ assert.ok(deviceBody.textContent.includes('Task timed out waiting for the agent response.'));
1467
+ assert.ok(deviceStatusBar.title.includes(focusedDevice.DeviceId));
1468
+ const controlCanvasBeforeRerender = deviceControlCanvas;
1469
+ manager.renderRemoteFleetDeviceForTest(deviceBody, buildDeviceNode(focusedDevice, hub.getStatus()));
1470
+ await wait(30);
1471
+ const controlCanvasAfterRerender = deviceBody.querySelector('[data-remote-fleet-control-node-canvas="true"]');
1472
+ assert.equal(
1473
+ controlCanvasAfterRerender,
1474
+ controlCanvasBeforeRerender,
1475
+ 'RemoteFleetDevice rerender should reuse the already-painted control canvas instead of flashing black');
1476
+ assert.equal(
1477
+ deviceBody.querySelector('[data-remote-fleet-control-node-placeholder="true"]'),
1478
+ null,
1479
+ 'RemoteFleetDevice rerender should not cover a restored control canvas with a waiting placeholder');
1480
+
1481
+ nodeShell.remove();
1482
+ emptyShell.remove();
1483
+ oneShell.remove();
1484
+ errorShell.remove();
1485
+ deviceBody.remove();
1486
+ await wait(2200);
1487
+
1488
+ console.log(`RemoteFleet render smoke OK (${SYNTHETIC_COUNT} synthetic devices, ${connectedCount} connected, ${aiCount} AI-ready)`);
1489
+ } finally {
1490
+ await hub.close();
1491
+ }