@mindexec/cli 0.2.101 → 0.2.103

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 (25) hide show
  1. package/package.json +2 -2
  2. package/remote-hub.js +51 -2
  3. package/scripts/remote-hub-smoke.mjs +8 -0
  4. package/wwwroot/_content/MindExecution.Shared/js/mind-map-css3d-manager.js +446 -19
  5. package/wwwroot/_content/MindExecution.Shared/js/mind-map-dnd.js +64 -3
  6. package/wwwroot/_content/MindExecution.Shared/js/mind-map-interactions.js +10 -7
  7. package/wwwroot/_content/MindExecution.Shared/js/mind-map-lod-renderer.js +3 -2
  8. package/wwwroot/_content/MindExecution.Shared/js/mind-map-node-search-worker.js +1 -0
  9. package/wwwroot/_content/MindExecution.Shared/js/mind-map-nodes.js +3 -2
  10. package/wwwroot/_content/MindExecution.Shared/js/mind-map-pipeline.js +9 -2
  11. package/wwwroot/_framework/MindExecution.Core.fc9cjbjplq.dll +0 -0
  12. package/wwwroot/_framework/{MindExecution.Kernel.7k773jan4j.dll → MindExecution.Kernel.pbzp3jfync.dll} +0 -0
  13. package/wwwroot/_framework/{MindExecution.Plugins.Admin.nr5ioavpvn.dll → MindExecution.Plugins.Admin.gxzwlji1cf.dll} +0 -0
  14. package/wwwroot/_framework/{MindExecution.Plugins.Business.qq63kom73x.dll → MindExecution.Plugins.Business.vtaey8c59y.dll} +0 -0
  15. package/wwwroot/_framework/{MindExecution.Plugins.Concept.w4znwcrl6x.dll → MindExecution.Plugins.Concept.ksc3wkuptm.dll} +0 -0
  16. package/wwwroot/_framework/{MindExecution.Plugins.Directory.u6p6pxpwxp.dll → MindExecution.Plugins.Directory.zc8ffaoknd.dll} +0 -0
  17. package/wwwroot/_framework/{MindExecution.Plugins.PlanMaster.0w4vr40lnz.dll → MindExecution.Plugins.PlanMaster.flzcb87jvl.dll} +0 -0
  18. package/wwwroot/_framework/{MindExecution.Plugins.YouTube.sdl5n9uv68.dll → MindExecution.Plugins.YouTube.q4tvods1po.dll} +0 -0
  19. package/wwwroot/_framework/{MindExecution.Shared.6us6j8zcea.dll → MindExecution.Shared.jv6r2n1bvg.dll} +0 -0
  20. package/wwwroot/_framework/{MindExecution.Web.xhlvm1d8ex.dll → MindExecution.Web.3b8az6ed0q.dll} +0 -0
  21. package/wwwroot/_framework/blazor.boot.json +21 -21
  22. package/wwwroot/index.html +3 -3
  23. package/wwwroot/service-worker-assets.js +30 -30
  24. package/wwwroot/service-worker.js +1 -1
  25. package/wwwroot/_framework/MindExecution.Core.cdplo34sb2.dll +0 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mindexec/cli",
3
- "version": "0.2.101",
3
+ "version": "0.2.103",
4
4
  "description": "MindExec local runtime and bridge CLI",
5
5
  "main": "server.js",
6
6
  "type": "module",
@@ -47,7 +47,7 @@
47
47
  "node": ">=20"
48
48
  },
49
49
  "dependencies": {
50
- "@mindexec/remote": "^0.1.15",
50
+ "@mindexec/remote": "^0.1.16",
51
51
  "@openai/codex-sdk": "^0.137.0",
52
52
  "chokidar": "^3.6.0",
53
53
  "cors": "^2.8.5",
package/remote-hub.js CHANGED
@@ -20,6 +20,7 @@ const MAX_SYNTHETIC_DEVICES = 1000;
20
20
  const DEFAULT_HOST_TARGET_LEASE_MS = 30000;
21
21
  const SYNTHETIC_FRAME_DATA_URL = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAABCAYAAAD0In+KAAAADElEQVR42mP8z8AAAAMBAQDJ/pLvAAAAAElFTkSuQmCC';
22
22
  const SYNTHETIC_FRAME_PAYLOAD = Buffer.from(SYNTHETIC_FRAME_DATA_URL.split(',')[1], 'base64');
23
+ const SYNTHETIC_FRAME_HASH = crypto.createHash('sha256').update(SYNTHETIC_FRAME_PAYLOAD).digest('hex').slice(0, 16);
23
24
 
24
25
  function isEnabledValue(value, fallback = true) {
25
26
  if (value === undefined || value === null || value === '') {
@@ -785,6 +786,9 @@ export function createRemoteHub(options = {}) {
785
786
  receivedAt: now,
786
787
  byteLength: 68,
787
788
  transport: 'synthetic',
789
+ contentHash: SYNTHETIC_FRAME_HASH,
790
+ captureMs: 0,
791
+ sameContentStreak: 0,
788
792
  dataUrl: SYNTHETIC_FRAME_DATA_URL,
789
793
  payload: SYNTHETIC_FRAME_PAYLOAD,
790
794
  accessToken: createFrameAccessToken()
@@ -1468,6 +1472,37 @@ export function createRemoteHub(options = {}) {
1468
1472
  return Buffer.from(base64, 'base64');
1469
1473
  }
1470
1474
 
1475
+ function buildFrameContentHash(message, payload) {
1476
+ const provided = safeString(message.contentHash || message.frameHash || message.hash, 96)
1477
+ .toLowerCase()
1478
+ .replace(/[^a-z0-9:_-]/g, '')
1479
+ .slice(0, 64);
1480
+ if (provided) {
1481
+ return provided;
1482
+ }
1483
+
1484
+ if (!Buffer.isBuffer(payload) || payload.length === 0) {
1485
+ return '';
1486
+ }
1487
+
1488
+ return crypto.createHash('sha256').update(payload).digest('hex').slice(0, 16);
1489
+ }
1490
+
1491
+ function readFrameCaptureMs(message) {
1492
+ const value = Number(message.captureMs);
1493
+ return Number.isFinite(value) && value >= 0
1494
+ ? Math.round(value)
1495
+ : 0;
1496
+ }
1497
+
1498
+ function computeSameContentStreak(previousFrame, contentHash) {
1499
+ if (!contentHash || !previousFrame?.contentHash || previousFrame.contentHash !== contentHash) {
1500
+ return 0;
1501
+ }
1502
+
1503
+ return clampNumber(Number(previousFrame.sameContentStreak || 0) + 1, 0, 1000000, 1);
1504
+ }
1505
+
1471
1506
  function applyThumbnailFrame(device, message, framePayload, transport = 'json-base64') {
1472
1507
  const frameData = Buffer.isBuffer(framePayload)
1473
1508
  ? ''
@@ -1489,6 +1524,8 @@ export function createRemoteHub(options = {}) {
1489
1524
  const mimeType = safeString(message.mimeType || message.format || 'image/jpeg', 80) || 'image/jpeg';
1490
1525
  const capturedAt = safeString(message.capturedAt, 80) || device.lastSeenAt;
1491
1526
  const payload = buildFramePayloadBuffer(framePayload, frameData);
1527
+ const contentHash = buildFrameContentHash(message, payload);
1528
+ const sameContentStreak = computeSameContentStreak(device.latestThumbnail, contentHash);
1492
1529
  device.latestThumbnail = {
1493
1530
  streamId: safeString(message.streamId, 128) || 'thumbnail',
1494
1531
  frameSeq,
@@ -1501,6 +1538,9 @@ export function createRemoteHub(options = {}) {
1501
1538
  receivedAt: device.lastSeenAt,
1502
1539
  byteLength,
1503
1540
  transport,
1541
+ contentHash,
1542
+ captureMs: readFrameCaptureMs(message),
1543
+ sameContentStreak,
1504
1544
  dataUrl: buildFrameDataUrl(framePayload, frameData, mimeType),
1505
1545
  payload,
1506
1546
  accessToken: createFrameAccessToken()
@@ -1511,7 +1551,9 @@ export function createRemoteHub(options = {}) {
1511
1551
  frameSeq,
1512
1552
  width: device.latestThumbnail.width,
1513
1553
  height: device.latestThumbnail.height,
1514
- transport
1554
+ transport,
1555
+ contentHash,
1556
+ sameContentStreak
1515
1557
  });
1516
1558
  return true;
1517
1559
  }
@@ -1550,6 +1592,8 @@ export function createRemoteHub(options = {}) {
1550
1592
  const mimeType = safeString(message.mimeType || message.format || 'image/jpeg', 80) || 'image/jpeg';
1551
1593
  const capturedAt = safeString(message.capturedAt, 80) || device.lastSeenAt;
1552
1594
  const payload = buildFramePayloadBuffer(framePayload, frameData);
1595
+ const contentHash = buildFrameContentHash(message, payload);
1596
+ const sameContentStreak = computeSameContentStreak(device.latestLiveFrame, contentHash);
1553
1597
  device.latestLiveFrame = {
1554
1598
  streamId,
1555
1599
  frameSeq,
@@ -1564,6 +1608,9 @@ export function createRemoteHub(options = {}) {
1564
1608
  receivedAt: device.lastSeenAt,
1565
1609
  byteLength,
1566
1610
  transport,
1611
+ contentHash,
1612
+ captureMs: readFrameCaptureMs(message),
1613
+ sameContentStreak,
1567
1614
  dataUrl: buildFrameDataUrl(framePayload, frameData, mimeType),
1568
1615
  payload,
1569
1616
  accessToken: createFrameAccessToken()
@@ -1578,7 +1625,9 @@ export function createRemoteHub(options = {}) {
1578
1625
  width: device.latestLiveFrame.width,
1579
1626
  height: device.latestLiveFrame.height,
1580
1627
  mode: device.latestLiveFrame.mode,
1581
- transport
1628
+ transport,
1629
+ contentHash,
1630
+ sameContentStreak
1582
1631
  });
1583
1632
  return true;
1584
1633
  }
@@ -169,10 +169,14 @@ try {
169
169
  assert.equal(binaryThumbnailDevice.latestThumbnail.streamId, 'smoke-thumb-binary');
170
170
  assert.equal(binaryThumbnailDevice.latestThumbnail.transport, 'binary');
171
171
  assert.equal(binaryThumbnailDevice.latestThumbnail.byteLength, smokePngFrame.length);
172
+ assert.equal(typeof binaryThumbnailDevice.latestThumbnail.contentHash, 'string');
173
+ assert.equal(binaryThumbnailDevice.latestThumbnail.contentHash.length, 16);
174
+ assert.equal(binaryThumbnailDevice.latestThumbnail.sameContentStreak, 1);
172
175
  assert.equal(binaryThumbnailDevice.counters.thumbnailFramesReceived, 2);
173
176
  const serializedBinaryThumbnail = hub.getDeviceThumbnail('smoke-device', { includeDataUrl: false });
174
177
  assert.equal(serializedBinaryThumbnail.streamId, 'smoke-thumb-binary');
175
178
  assert.equal(serializedBinaryThumbnail.frameSeq, 4);
179
+ assert.equal(serializedBinaryThumbnail.contentHash, binaryThumbnailDevice.latestThumbnail.contentHash);
176
180
  assert.ok(serializedBinaryThumbnail.framePath.includes('/api/remote/devices/smoke-device/thumbnail?'));
177
181
  assert.ok(!('dataUrl' in serializedBinaryThumbnail));
178
182
  assert.ok(!('payload' in serializedBinaryThumbnail));
@@ -242,10 +246,14 @@ try {
242
246
  assert.equal(binaryLiveDevice.latestLiveFrame.streamId, 'smoke-live');
243
247
  assert.equal(binaryLiveDevice.latestLiveFrame.transport, 'binary');
244
248
  assert.equal(binaryLiveDevice.latestLiveFrame.byteLength, smokePngFrame.length);
249
+ assert.equal(typeof binaryLiveDevice.latestLiveFrame.contentHash, 'string');
250
+ assert.equal(binaryLiveDevice.latestLiveFrame.contentHash.length, 16);
251
+ assert.equal(binaryLiveDevice.latestLiveFrame.sameContentStreak, 1);
245
252
  assert.equal(binaryLiveDevice.counters.liveFramesReceived, 2);
246
253
  const serializedBinaryLiveFrame = hub.getDeviceLiveFrame('smoke-device', { includeDataUrl: false });
247
254
  assert.equal(serializedBinaryLiveFrame.streamId, 'smoke-live');
248
255
  assert.equal(serializedBinaryLiveFrame.frameSeq, 5);
256
+ assert.equal(serializedBinaryLiveFrame.contentHash, binaryLiveDevice.latestLiveFrame.contentHash);
249
257
  assert.ok(serializedBinaryLiveFrame.framePath.includes('/api/remote/devices/smoke-device/live/frame?'));
250
258
  assert.ok(!('dataUrl' in serializedBinaryLiveFrame));
251
259
  assert.ok(!('payload' in serializedBinaryLiveFrame));