infinicode 2.8.43 → 2.8.44

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.
@@ -1319,40 +1319,67 @@ button.act:disabled{opacity:0.5;cursor:default;}
1319
1319
  return r.json();
1320
1320
  });
1321
1321
  }
1322
- function mergeSchedulerRobots(nodes){
1323
- return Promise.all([getJson('/robopark/api/robots'), getJson('/robopark/api/devices')]).then(function(data){
1324
- var rows = data[0], devices = data[1];
1325
- var deviceById = {}, deviceByName = {};
1326
- (Array.isArray(devices)?devices:[]).forEach(function(device){ deviceById[device.id] = device; if(device.name) deviceByName[device.name] = device; });
1327
- schedulerDevicesById = deviceById;
1328
- schedulerDevicesByName = deviceByName;
1329
- var merged = (nodes||[]).slice();
1330
- (Array.isArray(rows)?rows:[]).forEach(function(row){
1331
- var id = row.id || row.robot_id;
1332
- if(!id) return;
1333
- var name = row.name || id;
1334
- var duplicate = merged.some(function(n){
1335
- return n.schedulerRobotId===id || n.displayName===name || n.nodeId===id;
1336
- });
1337
- if(duplicate) return;
1338
- var device = deviceById[id] || {};
1339
- var status = String(device.status || row.status || '').toLowerCase();
1340
- var connected = ['online','detecting','connecting','running'].indexOf(status)>=0;
1341
- var keys = [String(id).toLowerCase(), String(name).toLowerCase()];
1342
- merged.push({
1343
- nodeId: 'scheduler-robot-'+id,
1344
- schedulerRobotId: id,
1345
- displayName: name,
1322
+ function mergeSchedulerRobots(nodes){
1323
+ return Promise.all([getJson('/robopark/api/robots'), getJson('/robopark/api/devices')]).then(function(data){
1324
+ var rows = data[0], devices = data[1];
1325
+ var deviceById = {}, deviceByName = {};
1326
+ function norm(v){ return String(v||'').trim().toLowerCase(); }
1327
+ (Array.isArray(devices)?devices:[]).forEach(function(device){
1328
+ deviceById[device.id] = device;
1329
+ if(device.name) deviceByName[norm(device.name)] = device;
1330
+ });
1331
+ schedulerDevicesById = deviceById;
1332
+ schedulerDevicesByName = deviceByName;
1333
+ var merged = (nodes||[]).slice();
1334
+ var candidates = (Array.isArray(rows)?rows:[]).slice();
1335
+ // Enrollment creates a devices row first; include it even when the
1336
+ // legacy robots table has not been populated for that device yet.
1337
+ (Array.isArray(devices)?devices:[]).forEach(function(device){
1338
+ var already = candidates.some(function(row){
1339
+ return norm(row.id||row.robot_id)===norm(device.id) || norm(row.name)===norm(device.name);
1340
+ });
1341
+ if(!already) candidates.push({id:device.id, name:device.name});
1342
+ });
1343
+ candidates.forEach(function(row){
1344
+ var id = row.id || row.robot_id;
1345
+ if(!id) return;
1346
+ var name = row.name || id;
1347
+ var device = deviceById[id] || deviceByName[norm(name)] || {};
1348
+ var status = String(device.status || row.status || '').toLowerCase();
1349
+ var heartbeat = device.last_heartbeat || row.last_heartbeat;
1350
+ var heartbeatAt = heartbeat ? Date.parse(heartbeat) : NaN;
1351
+ var heartbeatFresh = Number.isFinite(heartbeatAt) && (Date.now()-heartbeatAt) < 45_000;
1352
+ var connected = heartbeatFresh || ['online','detecting','connecting','running'].indexOf(status)>=0;
1353
+ var keys = [String(id).toLowerCase(), String(name).toLowerCase()];
1354
+ var existing = merged.find(function(n){
1355
+ return norm(n.schedulerRobotId)===norm(id)
1356
+ || norm(n.nodeId)===norm(id)
1357
+ || norm(n.displayName)===norm(name);
1358
+ });
1359
+ if(existing){
1360
+ existing.schedulerRobotId = id;
1361
+ existing.schedulerDeviceId = device.id || id;
1362
+ existing.displayName = existing.displayName || name;
1363
+ existing.connected = !!existing.connected || connected;
1364
+ existing.lastSeenAt = heartbeatAt && Number.isFinite(heartbeatAt) ? heartbeatAt : existing.lastSeenAt;
1365
+ existing.telemKeys = (existing.telemKeys||[]).concat(keys).filter(function(v,i,a){return a.indexOf(v)===i;});
1366
+ return;
1367
+ }
1368
+ merged.push({
1369
+ nodeId: 'scheduler-robot-'+id,
1370
+ schedulerRobotId: id,
1371
+ schedulerDeviceId: device.id || id,
1372
+ displayName: name,
1346
1373
  role: 'robot',
1347
1374
  platform: 'RoboPark robot',
1348
1375
  version: 'scheduler',
1349
1376
  capabilities: ['camera','microphone','voice'],
1350
1377
  connected: connected,
1351
1378
  load: 0,
1352
- lastSeenAt: device.last_heartbeat ? Date.parse(device.last_heartbeat) : (row.last_heartbeat ? Date.parse(row.last_heartbeat) : null),
1353
- telemKeys: keys,
1354
- });
1355
- });
1379
+ lastSeenAt: heartbeatAt && Number.isFinite(heartbeatAt) ? heartbeatAt : null,
1380
+ telemKeys: keys,
1381
+ });
1382
+ });
1356
1383
  return merged;
1357
1384
  }).catch(function(){ return nodes||[]; });
1358
1385
  }
@@ -18,6 +18,9 @@ const PATTERNS = [
18
18
  'cli.js serve', // source/dev invocation: `node dist/cli.js serve ...`
19
19
  'robopark serve',
20
20
  'robopark-cli.js serve',
21
+ // `robopark serve` detaches this child, so the Node launcher is gone while
22
+ // the Python scheduler remains. Match both Windows and POSIX separators.
23
+ 'scheduler.{0,3}main\\.py',
21
24
  'preview_agent.py',
22
25
  'app_pi_clean.py',
23
26
  ];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "infinicode",
3
- "version": "2.8.43",
3
+ "version": "2.8.44",
4
4
  "description": "OpenKernel — provider-agnostic AI execution kernel. Native coding agent + mission-driven execution runtime.",
5
5
  "type": "module",
6
6
  "main": "./dist/kernel/index.js",