You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
`- Paired device ${deviceLabel} is missing its approved operator scope baseline. Scope upgrades can get stuck in pairing-required until the device repairs or is re-approved.`,
331
-
);
351
+
issues.push({
352
+
kind: "missing-operator-scope-baseline",
353
+
deviceId: device.deviceId,
354
+
deviceLabel,
355
+
message: `Paired device ${deviceLabel} is missing its approved operator scope baseline. Scope upgrades can get stuck in pairing-required until the device repairs or is re-approved.`,
356
+
});
332
357
}
333
358
for(constroleofapprovedRoles){
334
359
consttoken=findTokenSummary(device,role);
@@ -342,9 +367,14 @@ function collectPairedRecordIssues(snapshot: DoctorPairingSnapshot): string[] {
342
367
role,
343
368
]);
344
369
if(!token){
345
-
lines.push(
346
-
`- Paired device ${deviceLabel} has no active ${role} device token even though the role is approved. This commonly ends in pairing-required or device-token-mismatch. Rotate a fresh token with ${rotateCommand}.`,
347
-
);
370
+
issues.push({
371
+
kind: "missing-active-role-token",
372
+
deviceId: device.deviceId,
373
+
deviceLabel,
374
+
role,
375
+
message: `Paired device ${deviceLabel} has no active ${role} device token even though the role is approved. This commonly ends in pairing-required or device-token-mismatch. Rotate a fresh token with ${rotateCommand}.`,
376
+
fixHint: `Rotate a fresh token with ${rotateCommand}.`,
377
+
});
348
378
continue;
349
379
}
350
380
if(
@@ -355,13 +385,22 @@ function collectPairedRecordIssues(snapshot: DoctorPairingSnapshot): string[] {
355
385
allowedScopes: approvedScopes,
356
386
})
357
387
){
358
-
lines.push(
359
-
`- Paired device ${deviceLabel} has a ${role} token outside the approved scope baseline [${formatScopes(approvedScopes)}]. Rotate it with ${rotateCommand}.`,
360
-
);
388
+
issues.push({
389
+
kind: "token-outside-approved-scope",
390
+
deviceId: device.deviceId,
391
+
deviceLabel,
392
+
role,
393
+
message: `Paired device ${deviceLabel} has a ${role} token outside the approved scope baseline [${formatScopes(approvedScopes)}]. Rotate it with ${rotateCommand}.`,
@@ -446,9 +485,14 @@ function collectLocalDeviceAuthIssues(snapshot: DoctorPairingSnapshot): string[]
446
485
if(approvedRoles.has(role)){
447
486
continue;
448
487
}
449
-
lines.push(
450
-
`- Local cached ${role} device auth for ${deviceLabel} no longer has a matching active gateway token, and that role is no longer approved for this device. Reconnect with shared gateway auth to refresh local auth, or remove the stale cached ${role} auth entry.`,
451
-
);
488
+
issues.push({
489
+
kind: "local-role-no-longer-approved",
490
+
deviceId: paired.deviceId,
491
+
deviceLabel,
492
+
role,
493
+
message: `Local cached ${role} device auth for ${deviceLabel} no longer has a matching active gateway token, and that role is no longer approved for this device. Reconnect with shared gateway auth to refresh local auth, or remove the stale cached ${role} auth entry.`,
494
+
fixHint: `Reconnect with shared gateway auth to refresh local auth, or remove the stale cached ${role} auth entry.`,
495
+
});
452
496
continue;
453
497
}
454
498
constrotateCommand=formatCliArgs([
@@ -463,27 +507,122 @@ function collectLocalDeviceAuthIssues(snapshot: DoctorPairingSnapshot): string[]
// Local device auth survives gateway restarts; compare timestamps to catch stale cached tokens.
465
509
if(entry.updatedAtMs<gatewayIssuedAtMs){
466
-
lines.push(
467
-
`- Local cached ${role} device token for ${deviceLabel} predates the gateway rotation. This is a stale device-token pattern and can fail with device token mismatch. Reconnect with shared gateway auth to refresh it, or rotate again with ${rotateCommand}.`,
468
-
);
510
+
issues.push({
511
+
kind: "local-token-stale",
512
+
deviceId: paired.deviceId,
513
+
deviceLabel,
514
+
role,
515
+
message: `Local cached ${role} device token for ${deviceLabel} predates the gateway rotation. This is a stale device-token pattern and can fail with device token mismatch. Reconnect with shared gateway auth to refresh it, or rotate again with ${rotateCommand}.`,
516
+
fixHint: `Reconnect with shared gateway auth to refresh it, or rotate again with ${rotateCommand}.`,
`- Local cached ${role} device scopes for ${deviceLabel} differ from the gateway record. Cached scopes [${formatScopes(cachedScopes)}], gateway scopes [${formatScopes(pairedScopes)}]. Reconnect with shared gateway auth to refresh it, or rotate with ${rotateCommand}.`,
476
-
);
523
+
issues.push({
524
+
kind: "local-scopes-mismatch",
525
+
deviceId: paired.deviceId,
526
+
deviceLabel,
527
+
role,
528
+
message: `Local cached ${role} device scopes for ${deviceLabel} differ from the gateway record. Cached scopes [${formatScopes(cachedScopes)}], gateway scopes [${formatScopes(pairedScopes)}]. Reconnect with shared gateway auth to refresh it, or rotate with ${rotateCommand}.`,
529
+
fixHint: `Reconnect with shared gateway auth to refresh it, or rotate with ${rotateCommand}.`,
constproblem=error.reason==="parse" ? "contains invalid JSON" : "could not be read";
484
542
return`- Device pairing store ${error.filePath}${problem}. OpenClaw refused to treat it as empty to avoid overwriting approved pairings. Fix the JSON or file permissions, or move it aside and re-pair devices.`;
0 commit comments