@mindexec/cli 0.2.456 → 0.2.458

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 (21) hide show
  1. package/package.json +77 -77
  2. package/remote-fast/osx-arm64/mindexec-remote-fast.dll +0 -0
  3. package/remote-fast/osx-x64/mindexec-remote-fast.dll +0 -0
  4. package/remote-fast/win-x64/mindexec-remote-fast.dll +0 -0
  5. package/scripts/remote-fleet-render-smoke.mjs +50 -229
  6. package/wwwroot/_content/MindExecution.Shared/js/mind-map-css3d-manager.js +301 -604
  7. package/wwwroot/_content/MindExecution.Shared/js/mind-map-pipeline.js +1326 -1323
  8. package/wwwroot/_framework/{MindExecution.Core.glgqkah960.dll → MindExecution.Core.2ch68iyy8o.dll} +0 -0
  9. package/wwwroot/_framework/{MindExecution.Kernel.1nb0zfmie1.dll → MindExecution.Kernel.dh617xfv36.dll} +0 -0
  10. package/wwwroot/_framework/{MindExecution.Plugins.Admin.4pdpv5q991.dll → MindExecution.Plugins.Admin.0sm50hbae9.dll} +0 -0
  11. package/wwwroot/_framework/{MindExecution.Plugins.Business.jpl2k4nnhh.dll → MindExecution.Plugins.Business.3wq01orrbu.dll} +0 -0
  12. package/wwwroot/_framework/{MindExecution.Plugins.Concept.rissr3n74r.dll → MindExecution.Plugins.Concept.z8yl28fa2a.dll} +0 -0
  13. package/wwwroot/_framework/{MindExecution.Plugins.Directory.tkopeqv16k.dll → MindExecution.Plugins.Directory.m7murp5oes.dll} +0 -0
  14. package/wwwroot/_framework/{MindExecution.Plugins.PlanMaster.jmjftycwo4.dll → MindExecution.Plugins.PlanMaster.yuyrbpf0vh.dll} +0 -0
  15. package/wwwroot/_framework/{MindExecution.Plugins.YouTube.drj98vf3ti.dll → MindExecution.Plugins.YouTube.rwxvn00rm2.dll} +0 -0
  16. package/wwwroot/_framework/{MindExecution.Shared.cbieupjmfp.dll → MindExecution.Shared.r9k48iyijb.dll} +0 -0
  17. package/wwwroot/_framework/{MindExecution.Web.xl8ygqgy0i.dll → MindExecution.Web.742aribkxm.dll} +0 -0
  18. package/wwwroot/_framework/blazor.boot.json +21 -21
  19. package/wwwroot/index.html +722 -722
  20. package/wwwroot/service-worker-assets.js +25 -25
  21. package/wwwroot/service-worker.js +1 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mindexec/cli",
3
- "version": "0.2.456",
3
+ "version": "0.2.458",
4
4
  "description": "MindExec local runtime and bridge CLI",
5
5
  "main": "server.js",
6
6
  "type": "module",
@@ -16,24 +16,24 @@
16
16
  "codex-runtime.js",
17
17
  "codex-model-catalog.js",
18
18
  "port-guard.cjs",
19
- "remote-fast/",
20
- "wwwroot/",
21
- "electron/",
22
- "scripts/",
19
+ "remote-fast/",
20
+ "wwwroot/",
21
+ "electron/",
22
+ "scripts/",
23
23
  "tree-sitter-grammars/",
24
24
  "README.md"
25
25
  ],
26
- "scripts": {
27
- "start": "node launch-bridge.cjs",
28
- "dev": "node launch-bridge.cjs --watch",
29
- "desktop:start": "electron electron/main.cjs",
30
- "desktop:build:win": "electron-builder --win --x64 --publish never",
31
- "test:desktop": "node electron/source-smoke.mjs",
32
- "test:desktop:win": "node electron/windows-package-smoke.mjs",
33
- "test:syntax": "node --check server.js && node --check remote-hub.js && node --check lzo1x.js && node --check mode4-atlas.js && node --check mode4-atlas-worker.js && node --check codex-runtime.js && node --check codex-model-catalog.js && node --check launch-bridge.cjs && node --check port-guard.cjs && node --check electron/main.cjs && node --check electron/source-smoke.mjs && node --check electron/windows-package-smoke.mjs && node --check scripts/setup-tree-sitter-grammars.mjs && node --check scripts/npm-fresh-install-smoke.mjs && node --check scripts/auth-session-smoke.mjs && node --check scripts/codex-model-catalog-smoke.mjs && node --check scripts/codex-sdk-runtime-smoke.mjs && node --check scripts/remote-hub-smoke.mjs && node --check scripts/remote-hub-scale-smoke.mjs && node --check scripts/remote-fleet-render-smoke.mjs && node --check scripts/remote-http-smoke.mjs && node --check scripts/remote-frame-ws-smoke.mjs && node --check scripts/remote-input-ws-smoke.mjs && node --check scripts/remote-agent-ws-smoke.mjs && node --check scripts/remote-agent-managed-smoke.mjs && node --check scripts/remote-registry-follower-smoke.mjs && node --check scripts/remote-agent-package-smoke.mjs && node --check scripts/remote-fast-live-rate-smoke.mjs && node --check scripts/remote-fast-mdm-browser-smoke.mjs",
34
- "test:codex-sdk": "node scripts/codex-sdk-runtime-smoke.mjs",
35
- "test:codex-sdk:live": "node scripts/codex-sdk-runtime-smoke.mjs --live",
36
- "test:codex-sdk:live-tools": "node scripts/codex-sdk-runtime-smoke.mjs --live-tools",
26
+ "scripts": {
27
+ "start": "node launch-bridge.cjs",
28
+ "dev": "node launch-bridge.cjs --watch",
29
+ "desktop:start": "electron electron/main.cjs",
30
+ "desktop:build:win": "electron-builder --win --x64 --publish never",
31
+ "test:desktop": "node electron/source-smoke.mjs",
32
+ "test:desktop:win": "node electron/windows-package-smoke.mjs",
33
+ "test:syntax": "node --check server.js && node --check remote-hub.js && node --check lzo1x.js && node --check mode4-atlas.js && node --check mode4-atlas-worker.js && node --check codex-runtime.js && node --check codex-model-catalog.js && node --check launch-bridge.cjs && node --check port-guard.cjs && node --check electron/main.cjs && node --check electron/source-smoke.mjs && node --check electron/windows-package-smoke.mjs && node --check scripts/setup-tree-sitter-grammars.mjs && node --check scripts/npm-fresh-install-smoke.mjs && node --check scripts/auth-session-smoke.mjs && node --check scripts/codex-model-catalog-smoke.mjs && node --check scripts/codex-sdk-runtime-smoke.mjs && node --check scripts/remote-hub-smoke.mjs && node --check scripts/remote-hub-scale-smoke.mjs && node --check scripts/remote-fleet-render-smoke.mjs && node --check scripts/remote-http-smoke.mjs && node --check scripts/remote-frame-ws-smoke.mjs && node --check scripts/remote-input-ws-smoke.mjs && node --check scripts/remote-agent-ws-smoke.mjs && node --check scripts/remote-agent-managed-smoke.mjs && node --check scripts/remote-registry-follower-smoke.mjs && node --check scripts/remote-agent-package-smoke.mjs && node --check scripts/remote-fast-live-rate-smoke.mjs && node --check scripts/remote-fast-mdm-browser-smoke.mjs",
34
+ "test:codex-sdk": "node scripts/codex-sdk-runtime-smoke.mjs",
35
+ "test:codex-sdk:live": "node scripts/codex-sdk-runtime-smoke.mjs --live",
36
+ "test:codex-sdk:live-tools": "node scripts/codex-sdk-runtime-smoke.mjs --live-tools",
37
37
  "test:codex-model-catalog": "node scripts/codex-model-catalog-smoke.mjs",
38
38
  "test:codex-model-catalog:live": "node scripts/codex-model-catalog-smoke.mjs --live",
39
39
  "test:auth": "node scripts/auth-session-smoke.mjs",
@@ -61,7 +61,7 @@
61
61
  "local",
62
62
  "ai"
63
63
  ],
64
- "author": "lovecrdm77",
64
+ "author": "lovecrdm77",
65
65
  "license": "MIT",
66
66
  "publishConfig": {
67
67
  "access": "public"
@@ -71,7 +71,7 @@
71
71
  },
72
72
  "dependencies": {
73
73
  "@ffmpeg-installer/ffmpeg": "^1.1.0",
74
- "@mindexec/remote": "^0.1.18",
74
+ "@mindexec/remote": "^0.1.18",
75
75
  "@openai/codex-sdk": "^0.144.1",
76
76
  "chokidar": "^3.6.0",
77
77
  "cors": "^2.8.5",
@@ -90,62 +90,62 @@
90
90
  "mindexec": "launch-bridge.cjs",
91
91
  "mind-bridge": "launch-bridge.cjs"
92
92
  },
93
- "devDependencies": {
94
- "electron": "43.2.0",
95
- "electron-builder": "26.15.3",
96
- "tree-sitter-wasms": "^0.1.13"
97
- },
98
- "build": {
99
- "appId": "com.mindexec.desktop",
100
- "productName": "MindExec",
101
- "copyright": "Copyright © 2026 lovecrdm77",
102
- "asar": false,
103
- "extraMetadata": {
104
- "main": "electron/main.cjs"
105
- },
106
- "directories": {
107
- "output": "../artifacts/electron"
108
- },
109
- "files": [
110
- "*.js",
111
- "*.cjs",
112
- "*.json",
113
- "electron/main.cjs",
114
- "remote-fast/**/*",
115
- "scripts/**/*",
116
- "tree-sitter-grammars/**/*",
117
- "wwwroot/**/*",
118
- "node_modules/**/*"
119
- ],
120
- "win": {
121
- "icon": "../MindExecution.Web/wwwroot/app-icon-1024.png",
122
- "executableName": "MindExec",
123
- "target": [
124
- {
125
- "target": "nsis",
126
- "arch": [
127
- "x64"
128
- ]
129
- },
130
- {
131
- "target": "portable",
132
- "arch": [
133
- "x64"
134
- ]
135
- }
136
- ]
137
- },
138
- "nsis": {
139
- "artifactName": "MindExec-Setup-${version}-${arch}.${ext}",
140
- "oneClick": false,
141
- "perMachine": false,
142
- "allowToChangeInstallationDirectory": true,
143
- "createDesktopShortcut": true,
144
- "createStartMenuShortcut": true,
145
- "shortcutName": "MindExec"
146
- },
147
- "portable": {
148
- "artifactName": "MindExec-Portable-${version}-${arch}.${ext}"
149
- }
150
- }
151
- }
93
+ "devDependencies": {
94
+ "electron": "43.2.0",
95
+ "electron-builder": "26.15.3",
96
+ "tree-sitter-wasms": "^0.1.13"
97
+ },
98
+ "build": {
99
+ "appId": "com.mindexec.desktop",
100
+ "productName": "MindExec",
101
+ "copyright": "Copyright © 2026 lovecrdm77",
102
+ "asar": false,
103
+ "extraMetadata": {
104
+ "main": "electron/main.cjs"
105
+ },
106
+ "directories": {
107
+ "output": "../artifacts/electron"
108
+ },
109
+ "files": [
110
+ "*.js",
111
+ "*.cjs",
112
+ "*.json",
113
+ "electron/main.cjs",
114
+ "remote-fast/**/*",
115
+ "scripts/**/*",
116
+ "tree-sitter-grammars/**/*",
117
+ "wwwroot/**/*",
118
+ "node_modules/**/*"
119
+ ],
120
+ "win": {
121
+ "icon": "../MindExecution.Web/wwwroot/app-icon-1024.png",
122
+ "executableName": "MindExec",
123
+ "target": [
124
+ {
125
+ "target": "nsis",
126
+ "arch": [
127
+ "x64"
128
+ ]
129
+ },
130
+ {
131
+ "target": "portable",
132
+ "arch": [
133
+ "x64"
134
+ ]
135
+ }
136
+ ]
137
+ },
138
+ "nsis": {
139
+ "artifactName": "MindExec-Setup-${version}-${arch}.${ext}",
140
+ "oneClick": false,
141
+ "perMachine": false,
142
+ "allowToChangeInstallationDirectory": true,
143
+ "createDesktopShortcut": true,
144
+ "createStartMenuShortcut": true,
145
+ "shortcutName": "MindExec"
146
+ },
147
+ "portable": {
148
+ "artifactName": "MindExec-Portable-${version}-${arch}.${ext}"
149
+ }
150
+ }
151
+ }
@@ -950,9 +950,11 @@ try {
950
950
 
951
951
  let cards = bodyView.querySelectorAll('article[data-device-id]');
952
952
  assert.equal(cards.length, connectedCount);
953
- assert.equal(bodyView.querySelector('[data-remote-fleet-match-count="true"]'), null);
954
- assert.equal(bodyView.querySelector('[data-remote-fleet-search="true"]'), null);
955
- assert.equal(bodyView.querySelectorAll('select').length, 0);
953
+ assert.ok(bodyView.querySelector('[data-remote-fleet-match-count="true"]'));
954
+ assert.ok(bodyView.querySelector('[data-remote-fleet-search="true"]'));
955
+ assert.equal(bodyView.querySelectorAll('select').length, 4);
956
+ assert.ok(bodyView.querySelector('[data-remote-fleet-task-composer="visible"]'));
957
+ assert.ok(bodyView.querySelector('[data-remote-fleet-task-input="true"]'));
956
958
  const deviceGrid = bodyView.querySelector('[data-remote-fleet-device-grid="true"]');
957
959
  assert.ok(deviceGrid);
958
960
  assert.match(deviceGrid.style.cssText, /padding:\s*0 4px;/);
@@ -1018,9 +1020,8 @@ try {
1018
1020
  const patchCard = Array.from(cards).find(card => card.dataset.deviceId === patchTarget.DeviceId);
1019
1021
  const patchPreview = patchCard?.querySelector('[data-remote-fleet-device-preview="tile"]');
1020
1022
  assert.ok(patchPreview);
1021
- const patchKind = String(patchPreview.dataset.remoteFleetFrameKind || '').toLowerCase() === 'live'
1022
- ? 'live'
1023
- : 'thumbnail';
1023
+ assert.notEqual(patchPreview.dataset.remoteFleetFrameKind, 'live');
1024
+ const patchKind = 'thumbnail';
1024
1025
  const patchUrl = `/api/remote/devices/${encodeURIComponent(patchTarget.DeviceId)}/${patchKind}?token=render-smoke-frame&seq=9999`;
1025
1026
  const patchCount = manager.applyRemoteFleetFramePatchesForTest(bodyView, [{
1026
1027
  deviceId: patchTarget.DeviceId,
@@ -1045,168 +1046,13 @@ try {
1045
1046
  assert.equal(patchPreview.querySelector('img[data-remote-fleet-frame-image="true"]')?.dataset.remoteFleetFrameUrl, patchUrl);
1046
1047
  assert.equal(patchPreview.querySelector('[data-remote-fleet-frame-badge="true"]'), null);
1047
1048
 
1048
- const objectUrlCountBeforeBinary = diagnostics.objectUrlCalls.length;
1049
- const imageBitmapCountBeforeBinary = diagnostics.imageBitmapCalls.length;
1050
- const drawCountBeforeBinary = document.canvasDrawCalls.length;
1051
- const binaryPatchCount = manager.applyRemoteFleetFramePatchesForTest(bodyView, [{
1052
- deviceId: patchTarget.DeviceId,
1053
- kind: 'live',
1054
- frameSeq: 10000,
1055
- frameUrl: '',
1056
- streamId: 'render-smoke-binary-live',
1057
- contentHash: 'render-smoke-binary-live-10000',
1058
- receivedAt: new Date().toISOString(),
1059
- _remoteFleetPayloadBlob: new Blob([new Uint8Array([0xff, 0xd8, 0xff, 0xd9])], { type: 'image/jpeg' }),
1060
- _remoteFleetBinaryFrame: true
1061
- }]);
1062
- assert.equal(binaryPatchCount, 1);
1063
- await wait(20);
1064
- const binaryCanvas = patchPreview.querySelector('canvas[data-remote-fleet-frame-canvas="true"]');
1065
- const binaryImage = patchPreview.querySelector('img[data-remote-fleet-frame-image="true"]');
1066
- assert.equal(patchPreview.dataset.remoteFleetFrameKind, 'live');
1067
- assert.equal(patchPreview.dataset.remoteFleetFrameSeq, '10000');
1068
- assert.equal(binaryCanvas?.dataset.remoteFleetFrameSeq, '10000');
1069
- assert.equal(binaryCanvas?.style.display, 'block');
1070
- assert.equal(binaryImage?.style.display, 'none');
1071
- assert.equal(diagnostics.imageBitmapCalls.length, imageBitmapCountBeforeBinary + 1);
1072
- assert.equal(diagnostics.objectUrlCalls.length, objectUrlCountBeforeBinary);
1073
- const binaryDrawCalls = document.canvasDrawCalls.slice(drawCountBeforeBinary);
1074
- assert.ok(
1075
- binaryDrawCalls.some(call => call.op === 'drawImage'),
1076
- 'expected binary Blob frame to draw directly to canvas');
1077
- assert.equal(
1078
- binaryDrawCalls.some(call => call.op === 'clearRect' || call.op === 'fillRect'),
1079
- false,
1080
- 'binary Blob frame paint must not clear/fill the canvas before drawing');
1081
- assert.ok(
1082
- Number(moduleRef._forceUpdateFrames || 0) >= 2,
1083
- 'binary live frame commits must wake the passive MDM CSS3D frame loop');
1084
- assert.equal(moduleRef._lastAnimationWakeReason, 'remote-live-css3d-frame');
1085
- assert.ok(
1086
- diagnostics.runtimeTrace.some(event => event.type === 'remote.frame.css3dWake'),
1087
- 'binary live frame commits must trace the MDM CSS3D wake path');
1088
- const binaryCanvasBeforeRerender = binaryCanvas;
1089
-
1090
- const liveOverlayCard = document.createElement('div');
1091
- liveOverlayCard.dataset.nodeId = 'remote-fleet-render-smoke';
1092
- liveOverlayCard.dataset.sourceKind = 'live';
1093
- liveOverlayCard.dataset.liveInteractive = 'true';
1094
- liveOverlayCard.style.display = 'block';
1095
- moduleRef._textOverlayV2State.cards.set('selection:remote-fleet-render-smoke', liveOverlayCard);
1096
- moduleRef._forceUpdateFrames = 0;
1097
- moduleRef._animationWakeCount = 0;
1098
- moduleRef._lastAnimationWakeReason = '';
1099
-
1100
- await wait(20);
1101
- const liveWs = diagnostics.webSocketConnections.find(connection =>
1102
- String(connection?.url || '').includes('/api/remote/atlas/ws'));
1103
- assert.ok(
1104
- liveWs,
1105
- `expected MDM render to open the Mode 4 Atlas WebSocket: ${diagnostics.webSocketConnections.map(connection => connection.url).join(', ')}`
1106
- );
1107
- assert.equal(liveWs.readyState, 1, 'Mode 4 Atlas WebSocket should be open before rerender');
1108
- const wsCountBeforeRerender = diagnostics.webSocketConnections.length;
1109
- const wsCloseCountBeforeRerender = liveWs.closeCount;
1110
- const websocketFrameSeq = 10001;
1111
- liveWs.onmessage?.({
1112
- data: JSON.stringify({
1113
- type: 'Mode4AtlasLayout',
1114
- tiles: [{
1115
- deviceId: patchTarget.DeviceId,
1116
- x: 0,
1117
- y: 0,
1118
- width: 64,
1119
- height: 36
1120
- }]
1121
- })
1122
- });
1123
- liveWs.onmessage?.({
1124
- data: new Blob([encodeRemoteBinaryFrame({
1125
- type: 'remote.frame.binary',
1126
- deviceId: patchTarget.DeviceId,
1127
- kind: 'live',
1128
- frameSeq: websocketFrameSeq,
1129
- streamId: 'render-smoke-ws-live',
1130
- contentHash: `render-smoke-ws-live-${websocketFrameSeq}`,
1131
- mimeType: 'image/jpeg',
1132
- frameMode: 'mode4-h264-atlas',
1133
- width: 64,
1134
- height: 36,
1135
- capturedAt: new Date().toISOString(),
1136
- receivedAt: new Date().toISOString()
1137
- })])
1138
- });
1139
- await waitFor(
1140
- () => patchPreview.dataset.remoteFleetFrameSeq === String(websocketFrameSeq)
1141
- );
1142
- assert.equal(
1143
- patchPreview.dataset.remoteFleetFrameSeq,
1144
- String(websocketFrameSeq),
1145
- JSON.stringify(diagnostics.runtimeTrace.slice(-12)));
1146
- assert.ok(
1147
- diagnostics.runtimeTrace.some(event =>
1148
- event.type === 'remote.atlas.painted' &&
1149
- Number(event.frameSeq || 0) === websocketFrameSeq),
1150
- 'Mode 4 Atlas frame must paint its configured device tile');
1151
-
1152
- manager.renderRemoteFleetMonitorForTest(bodyView, buildMonitorNode(devices, hub.getStatus({ includeSecrets: true }), latestTaskBatch, recentTaskBatches));
1153
- await wait(30);
1154
- assert.equal(
1155
- liveWs.closeCount,
1156
- wsCloseCountBeforeRerender,
1157
- 'MDM rerender must not close the active Mode 4 Atlas WebSocket');
1158
- assert.equal(
1159
- diagnostics.webSocketConnections.length,
1160
- wsCountBeforeRerender,
1161
- 'MDM rerender must reuse the active Mode 4 Atlas WebSocket instead of opening a replacement');
1162
- const rerenderedPatchPreview = bodyView
1163
- .querySelector(`article[data-device-id="${patchTarget.DeviceId}"]`)
1164
- ?.querySelector('[data-remote-fleet-device-preview="tile"]');
1165
- assert.ok(rerenderedPatchPreview);
1166
- assert.equal(rerenderedPatchPreview.dataset.remoteFleetFrameSeq, String(websocketFrameSeq));
1167
- const rerenderedPatchCanvas = rerenderedPatchPreview.querySelector('canvas[data-remote-fleet-frame-canvas="true"]');
1168
- assert.equal(rerenderedPatchCanvas?.style.display, 'block');
1169
- assert.equal(
1170
- rerenderedPatchCanvas,
1171
- binaryCanvasBeforeRerender,
1172
- 'MDM rerender should reuse the already-painted canvas instead of flashing a blank replacement');
1173
-
1174
- const otherBoardNodeId = 'remote-fleet-render-smoke-other-board';
1175
- const { nodeShell: otherBoardShell, bodyView: otherBoardBodyView } =
1176
- createRemoteFleetTemplateShell(document, focusedDevice.DeviceId, otherBoardNodeId);
1177
- document.body.appendChild(otherBoardShell);
1178
- manager.renderRemoteFleetMonitorForTest(
1179
- otherBoardBodyView,
1180
- buildMonitorNode(
1181
- devices,
1182
- hub.getStatus({ includeSecrets: true }),
1183
- latestTaskBatch,
1184
- recentTaskBatches,
1185
- '',
1186
- otherBoardNodeId));
1187
- await wait(30);
1188
- const otherBoardPatchPreview = otherBoardBodyView
1189
- .querySelector(`article[data-device-id="${patchTarget.DeviceId}"]`)
1190
- ?.querySelector('[data-remote-fleet-device-preview="tile"]');
1191
- assert.ok(otherBoardPatchPreview);
1192
- assert.ok(
1193
- diagnostics.webSocketConnections.length > wsCountBeforeRerender,
1194
- 'a different-board MDM must own a separate Mode 4 Atlas session');
1195
- assert.ok(diagnostics.runtimeTrace.some(event =>
1196
- event.type === 'remote.atlas.wsOpen'
1197
- && event.nodeId === otherBoardNodeId));
1198
- otherBoardShell.remove();
1199
-
1200
1049
  const controlCard = bodyView.querySelector(`article[data-device-id="${patchTarget.DeviceId}"]`);
1201
1050
  assert.ok(controlCard);
1202
1051
  controlCard.dispatchEvent({ type: 'dblclick', button: 0 });
1203
1052
  await wait(30);
1204
1053
  assert.equal(document.body.querySelector('[data-remote-fleet-control-popup="true"]'), null);
1205
- const addControlNodeCall = dotNetCalls.find(call =>
1206
- call.methodName === 'AddRemoteFleetDeviceNodeFromJs'
1207
- && call.args[0] === 'remote-fleet-render-smoke'
1208
- && call.args[1] === patchTarget.DeviceId);
1209
- assert.ok(addControlNodeCall, 'double-clicking an MDM tile should create a remote-control canvas node');
1054
+ const addControlNodeCall = dotNetCalls.find(call => call.methodName === 'AddRemoteFleetDeviceNodeFromJs');
1055
+ assert.equal(addControlNodeCall, undefined, 'MDM thumbnails must not create an expanded device node');
1210
1056
 
1211
1057
  const alternateDevice = devices.find(device =>
1212
1058
  device.Connected === true
@@ -1222,10 +1068,20 @@ try {
1222
1068
  assert.equal(selectedAfterClick?.querySelector('[data-remote-fleet-selected-indicator="true"]'), null);
1223
1069
  const livePanel = bodyView.querySelector('[data-remote-fleet-live-panel="true"]');
1224
1070
  assert.equal(livePanel, null);
1225
- assert.equal(bodyView.querySelector('[data-remote-fleet-action="task-visible"]'), null);
1226
- assert.equal(bodyView.querySelector('[data-remote-fleet-action="task-connected"]'), null);
1227
- assert.equal(bodyView.querySelector('[data-remote-fleet-task-input="true"]'), null);
1228
- assert.equal(bodyView.querySelector('[data-remote-fleet-ai-toggle="true"]'), null);
1071
+ assert.ok(bodyView.querySelector('[data-remote-fleet-action="task-selected"]'));
1072
+ assert.ok(bodyView.querySelector('[data-remote-fleet-action="task-connected"]'));
1073
+ assert.ok(bodyView.querySelector('[data-remote-fleet-task-input="true"]'));
1074
+ assert.ok(bodyView.querySelector('[data-remote-fleet-ai-toggle="true"]'));
1075
+ const selectedTaskInput = bodyView.querySelector('[data-remote-fleet-task-input="true"]');
1076
+ const selectedTaskButton = bodyView.querySelector('[data-remote-fleet-action="task-selected"]');
1077
+ selectedTaskInput.value = 'Inspect Git status and report the result.';
1078
+ selectedTaskButton.dispatchEvent({ type: 'click' });
1079
+ await wait(20);
1080
+ const selectedTaskCall = dotNetCalls.find(call =>
1081
+ call.methodName === 'DispatchRemoteFleetTaskFromJs'
1082
+ && call.args[0] === 'remote-fleet-render-smoke'
1083
+ && call.args[1] === alternateDevice.DeviceId);
1084
+ assert.ok(selectedTaskCall, 'selected thumbnail must target its agent command');
1229
1085
  assert.equal(bodyView.textContent.includes('all devices, no paging'), false);
1230
1086
  assert.equal(bodyView.textContent.includes('Host: Inactive'), false);
1231
1087
  assert.equal(bodyView.textContent.includes('No screen'), false);
@@ -1276,40 +1132,29 @@ try {
1276
1132
  assert.equal(bodyView.querySelector('[data-remote-fleet-action="copy-command"]'), null);
1277
1133
  assert.equal(bodyView.querySelector('[data-remote-fleet-action="refresh"]'), null);
1278
1134
  assert.equal(bodyView.querySelector('[data-remote-fleet-auto-toggle="true"]'), null);
1279
- assert.equal(bodyView.textContent.includes('synthetic-render-ai'), false);
1280
- assert.equal(bodyView.textContent.includes('Task timed out waiting for the agent response.'), false);
1135
+ assert.equal(bodyView.textContent.includes('synthetic-render-ai'), true);
1136
+ assert.equal(bodyView.textContent.includes('Task timed out waiting for the agent response.'), true);
1281
1137
  const batchSummary = bodyView.querySelector('[data-remote-fleet-task-batch="true"]');
1282
- assert.equal(batchSummary, null);
1138
+ assert.ok(batchSummary);
1283
1139
  const batchHistory = bodyView.querySelector('[data-remote-fleet-task-history="true"]');
1284
- assert.equal(batchHistory, null);
1140
+ assert.ok(batchHistory);
1285
1141
  const resultPanel = bodyView.querySelector('[data-remote-fleet-task-results="true"]');
1286
- assert.equal(resultPanel, null);
1142
+ assert.ok(resultPanel);
1287
1143
  assert.ok(devices.some(device => /^synthetic-response-/.test(device.LatestTaskResultResponseId)));
1288
1144
  await wait(20);
1289
1145
  const liveStartCalls = dotNetCalls
1290
1146
  .filter(call => call.methodName === 'StartRemoteFleetLiveStreamFromJs');
1291
- const subscribeMessages = diagnostics.webSocketSends
1292
- .map(send => {
1293
- try {
1294
- return JSON.parse(send.payload);
1295
- } catch {
1296
- return null;
1297
- }
1298
- })
1299
- .filter(Boolean);
1300
- const atlasConfigure = subscribeMessages.find(message =>
1301
- message.type === 'configure');
1302
- assert.ok(diagnostics.fetchCalls.some(call => call.url.includes('/api/status?remoteFrames=ws')));
1303
- assert.ok(diagnostics.webSocketConnections.length >= 1, 'expected MDM render to open Mode 4 Atlas WebSocket');
1304
- assert.ok(atlasConfigure, 'expected MDM render to configure the Mode 4 Atlas WebSocket');
1305
- assert.equal(atlasConfigure.fps, 20);
1306
- assert.equal(atlasConfigure.width, 1920);
1307
- assert.equal(atlasConfigure.height, 1080);
1308
- assert.equal(atlasConfigure.tileWidth, 320);
1309
- assert.equal(atlasConfigure.tileHeight, 180);
1310
- assert.ok(atlasConfigure.deviceIds.length > 1, 'expected visible connected devices in Atlas configuration');
1311
- assert.ok(diagnostics.runtimeTrace.some(event => event.type === 'remote.live.wsAutoStartRequested'));
1312
- assert.equal(liveStartCalls.length, 0, 'WebSocket live path must not call DotNet live-start fallback');
1147
+ assert.equal(liveStartCalls.length, 0, 'thumbnail-only MDM must not start live streams');
1148
+ assert.equal(
1149
+ diagnostics.webSocketConnections.some(connection =>
1150
+ String(connection?.url || '').includes('/api/remote/atlas/ws')
1151
+ || String(connection?.url || '').includes('/api/remote/frames/ws')),
1152
+ false,
1153
+ 'thumbnail-only MDM must not open live frame WebSockets');
1154
+ assert.equal(
1155
+ diagnostics.fetchCalls.some(call => call.url.includes('/api/status?remoteFrames=ws')),
1156
+ false,
1157
+ 'thumbnail-only MDM must not initialize live-frame transport');
1313
1158
  await wait(320);
1314
1159
  assert.ok(dotNetCalls.some(call => call.methodName === 'RefreshRemoteFleetMonitorNodeFromJs'));
1315
1160
  assert.equal(bodyView.dataset.remoteFleetTaskFollowKey, 'render-smoke-batch');
@@ -1318,10 +1163,10 @@ try {
1318
1163
  const feedback = bodyView.querySelector('[data-remote-fleet-task-feedback="true"]');
1319
1164
  assert.ok(feedback);
1320
1165
 
1321
- assert.equal(bodyView.querySelector('[data-remote-fleet-ai-toggle="true"]'), null);
1322
- assert.equal(dotNetCalls.some(call =>
1323
- call.methodName === 'DispatchRemoteFleetTaskBatchFromJs'
1324
- || call.methodName === 'DispatchRemoteFleetTaskFromJs'), false);
1166
+ assert.ok(bodyView.querySelector('[data-remote-fleet-ai-toggle="true"]'));
1167
+ assert.ok(dotNetCalls.some(call =>
1168
+ call.methodName === 'DispatchRemoteFleetTaskFromJs'
1169
+ && call.args[1] === alternateDevice.DeviceId));
1325
1170
 
1326
1171
  const { nodeShell: emptyShell, bodyView: emptyBody } = createRemoteFleetTemplateShell(document);
1327
1172
  document.body.appendChild(emptyShell);
@@ -1409,12 +1254,12 @@ try {
1409
1254
  && message.type === 'subscribe'
1410
1255
  && message.nodeId === 'remote-device-render-smoke'
1411
1256
  && message.autoStartLive === true
1412
- && message.fps === 30
1413
- && message.mode === 'mode3-h264-hw'
1414
- && message.streamPurpose === 'control'
1257
+ && message.fps === 2
1258
+ && message.mode === 'mode2-lzo'
1259
+ && message.streamPurpose === 'wall'
1415
1260
  && Array.isArray(message.deviceIds)
1416
1261
  && message.deviceIds.includes(focusedDevice.DeviceId));
1417
- assert.ok(deviceControlSubscribe, 'RemoteFleetDevice node should subscribe to 30fps Mode 3 control frames');
1262
+ assert.ok(deviceControlSubscribe, 'Remote workstation should subscribe to a 2fps view-only observation stream');
1418
1263
  const deviceControlWs = diagnostics.webSocketConnections
1419
1264
  .filter(ws => ws.url.includes('/api/remote/frames/ws'))
1420
1265
  .at(-1);
@@ -1469,36 +1314,12 @@ try {
1469
1314
  });
1470
1315
  await wait(50);
1471
1316
  const inputWsSends = diagnostics.webSocketSends
1472
- .filter(send => send.url.includes('/api/remote/input/ws'))
1473
- .map(send => {
1474
- try {
1475
- return JSON.parse(send.payload);
1476
- } catch {
1477
- return null;
1478
- }
1479
- })
1480
- .filter(Boolean);
1481
- assert.ok(inputWsSends.length >= 3, 'RemoteFleetDevice node should send pointer and keyboard input over the input WebSocket');
1482
- const pointerDown = inputWsSends.find(message => message.input?.type === 'pointerDown');
1483
- const keyDown = inputWsSends.find(message => message.input?.type === 'keyDown');
1484
- const keyUp = inputWsSends.find(message => message.input?.type === 'keyUp');
1485
- assert.ok(pointerDown);
1486
- assert.ok(keyDown);
1487
- assert.ok(keyUp);
1488
- assert.equal(pointerDown.nodeId, 'remote-device-render-smoke');
1489
- assert.equal(pointerDown.deviceId, focusedDevice.DeviceId);
1490
- assert.equal(pointerDown.input.button, 'left');
1491
- assert.ok(pointerDown.input.controlLeaseId);
1492
- assert.ok(pointerDown.input.normalizedX >= 0 && pointerDown.input.normalizedX <= 1);
1493
- assert.ok(pointerDown.input.normalizedY >= 0 && pointerDown.input.normalizedY <= 1);
1494
- assert.equal(keyDown.input.key, 'A');
1495
- assert.equal(keyDown.input.code, 'KeyA');
1496
- assert.equal(keyUp.input.key, 'A');
1497
- assert.equal(keyUp.input.code, 'KeyA');
1317
+ .filter(send => send.url.includes('/api/remote/input/ws'));
1318
+ assert.equal(inputWsSends.length, 0, 'Remote workstation must remain view-only and send no pointer or keyboard input');
1498
1319
  assert.equal(
1499
1320
  dotNetCalls.filter(call => call.methodName === 'SendRemoteFleetInputFromJs').length,
1500
1321
  0,
1501
- 'WebSocket input path should not use the slower DotNet input fallback in the happy path');
1322
+ 'View-only workstation must not use the DotNet input fallback');
1502
1323
  assert.ok(deviceBody.querySelector('[data-remote-fleet-action="refresh-device"]'));
1503
1324
  assert.ok(deviceBody.querySelector('[data-remote-fleet-action="task-device"]'));
1504
1325
  assert.ok(deviceBody.textContent.includes('Task timed out waiting for the agent response.'));