@songsid/agend 2.2.0-beta.12 → 2.2.0-beta.14
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.
- package/dist/cli.js +12 -6
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +1 -0
- package/dist/config.js +2 -1
- package/dist/config.js.map +1 -1
- package/dist/daemon.d.ts +1 -0
- package/dist/daemon.js +31 -4
- package/dist/daemon.js.map +1 -1
- package/dist/fleet-manager.d.ts +14 -5
- package/dist/fleet-manager.js +54 -52
- package/dist/fleet-manager.js.map +1 -1
- package/dist/instance-avatar.d.ts +1 -1
- package/dist/instance-avatar.js +7 -4
- package/dist/instance-avatar.js.map +1 -1
- package/dist/locale.js +48 -22
- package/dist/locale.js.map +1 -1
- package/dist/restart-progress.d.ts +0 -2
- package/dist/restart-progress.js +0 -2
- package/dist/restart-progress.js.map +1 -1
- package/dist/topic-commands.d.ts +4 -0
- package/dist/topic-commands.js +9 -2
- package/dist/topic-commands.js.map +1 -1
- package/dist/transcript-sources.js +6 -1
- package/dist/transcript-sources.js.map +1 -1
- package/dist/ui/chat-strings.js +10 -10
- package/dist/ui/chat-tour.js +17 -14
- package/dist/ui/panel-chat.js +9 -9
- package/dist/ui/panel-fleet.js +15 -2
- package/dist/ui/panel-log.js +2 -2
- package/dist/ui/panel-needs.js +10 -7
- package/dist/ui/panel-settings.js +9 -5
- package/dist/ui/settings-dialogs.js +2 -2
- package/dist/ui/settings-model.js +3 -1
- package/dist/ui/settings-strings.js +8 -8
- package/dist/ui/shared/app.css +3 -2
- package/dist/ui/shared/header-tools.js +22 -10
- package/dist/ui/shared/panel-view.js +7 -4
- package/dist/ui/shared/signin.js +15 -9
- package/dist/ui/shared/ui-icons.js +1 -0
- package/dist/ui/signin.html +8 -3
- package/dist/update-launch.js +12 -6
- package/dist/update-launch.js.map +1 -1
- package/package.json +1 -1
package/dist/fleet-manager.d.ts
CHANGED
|
@@ -439,7 +439,6 @@ export declare class FleetManager implements FleetContext, LifecycleContext, Arc
|
|
|
439
439
|
private updateProgressTimer;
|
|
440
440
|
private updateProgressEditRunning;
|
|
441
441
|
private lastUpdateProgressText;
|
|
442
|
-
private updateCompletionTipText;
|
|
443
442
|
/**
|
|
444
443
|
* #1660: an adopted update whose retire outcome is still owed. The
|
|
445
444
|
* completion summary was (or will be) posted; this watch appends the
|
|
@@ -1904,9 +1903,13 @@ export declare class FleetManager implements FleetContext, LifecycleContext, Arc
|
|
|
1904
1903
|
private webImageCaches;
|
|
1905
1904
|
private webImageCache;
|
|
1906
1905
|
/**
|
|
1907
|
-
*
|
|
1908
|
-
* whatever an instance still names — #1635 review)
|
|
1906
|
+
* The bots instances and ClassicBot rooms speak through, by connections configured now (a connection removed from
|
|
1907
|
+
* fleet.yaml is nobody's, whatever an instance still names — #1635 review). `own`: instance → its own bot (not the
|
|
1908
|
+
* primary, answering for it alone). `speaking` (#1867): instance → the bot it speaks through — its own, a shared one,
|
|
1909
|
+
* or, with none configured for it, the primary.
|
|
1909
1910
|
*/
|
|
1911
|
+
private webBots;
|
|
1912
|
+
/** instance → the connection that is its own bot (see webBots). */
|
|
1910
1913
|
private ownBots;
|
|
1911
1914
|
/**
|
|
1912
1915
|
* The bot a connection is now: its running adapter and that bot's own user id. Everything cached for an own bot is
|
|
@@ -1922,9 +1925,15 @@ export declare class FleetManager implements FleetContext, LifecycleContext, Arc
|
|
|
1922
1925
|
private webAccent;
|
|
1923
1926
|
/** The cache key of an own bot's avatar, and its loader (which refuses an answer from a bot no longer there). */
|
|
1924
1927
|
private botAvatarSource;
|
|
1925
|
-
/**
|
|
1928
|
+
/**
|
|
1929
|
+
* One instance's avatar and ring for the status frame. Synchronous: what is cached now; fetches run behind. The bot
|
|
1930
|
+
* is its own, else the one it speaks through (#1867) — one cache entry per bot, so a shared bot is fetched once.
|
|
1931
|
+
*/
|
|
1926
1932
|
private webIdentityImage;
|
|
1927
|
-
/**
|
|
1933
|
+
/**
|
|
1934
|
+
* GET /ui/img/bot|avatar/<key>: what is cached, never a fetch. Only a connection some instance or room speaks
|
|
1935
|
+
* through (#1867), or a known instance's upload.
|
|
1936
|
+
*/
|
|
1928
1937
|
webImage(kind: "bot" | "avatar", key: string): CachedImage | null;
|
|
1929
1938
|
/**
|
|
1930
1939
|
* #1682 GET /ui/mentions: names for the mention ids a page found in what it rendered — never a Discord request; in order:
|
package/dist/fleet-manager.js
CHANGED
|
@@ -178,7 +178,7 @@ import { assertExplicitInstanceRemoval } from "./instance-removal.js";
|
|
|
178
178
|
import { KNOWN_BACKENDS, validateFleetConfig } from "./config-validator.js";
|
|
179
179
|
import { isRemovedBackend, removedBackendMessage } from "./backend/removed.js";
|
|
180
180
|
import { presentationState, interactionSummary, sameInteractionOwner } from "./interaction-observation.js";
|
|
181
|
-
import { readLastInboundAt } from "./daemon.js";
|
|
181
|
+
import { DEFAULT_STUCK_TIMEOUT_MS, readLastInboundAt } from "./daemon.js";
|
|
182
182
|
import { clearPausedMarker, readPausedAt, readPauseReason, writePausedMarker } from "./pause-marker.js";
|
|
183
183
|
import { readBackgroundWorkEndedMarker } from "./background-work-ended.js";
|
|
184
184
|
import { DEFAULT_WARM_OVERFLOW, WakeCoordinator } from "./wake-coordinator.js";
|
|
@@ -189,7 +189,7 @@ import { isSetupComplete, markSetupComplete } from "./setup-marker.js";
|
|
|
189
189
|
import { manualCleanupMessage, reapStaleTunnel } from "./tunnel/lease.js";
|
|
190
190
|
import { buildToolPermissionsNotice } from "./tool-permissions-notice.js";
|
|
191
191
|
import { NeedsYouHub } from "./needs-you-hub.js";
|
|
192
|
-
import { WEB_CHAT_NOTICE,
|
|
192
|
+
import { WEB_CHAT_NOTICE, claimNotice, hasWebChat, releaseNotice, upgradeNoticesPath } from "./upgrade-notices.js";
|
|
193
193
|
import { GENERAL_PAUSE_ERROR, isGeneralInstance } from "./general-instance.js";
|
|
194
194
|
import { buildOrgChart } from "./web-org.js";
|
|
195
195
|
import { CacheService, WINDOWS } from "./cache-service.js";
|
|
@@ -762,7 +762,6 @@ export class FleetManager {
|
|
|
762
762
|
updateProgressTimer = null;
|
|
763
763
|
updateProgressEditRunning = false;
|
|
764
764
|
lastUpdateProgressText = null;
|
|
765
|
-
updateCompletionTipText = null;
|
|
766
765
|
/**
|
|
767
766
|
* #1660: an adopted update whose retire outcome is still owed. The
|
|
768
767
|
* completion summary was (or will be) posted; this watch appends the
|
|
@@ -1662,6 +1661,7 @@ export class FleetManager {
|
|
|
1662
1661
|
content: payload.content,
|
|
1663
1662
|
delivery_id: claimed.deliveryId,
|
|
1664
1663
|
delivery_attempt: String(claimed.attemptNo),
|
|
1664
|
+
...(isSilentScheduleDelivery(claimed) ? { silent_schedule: true } : {}),
|
|
1665
1665
|
}, { waitForIdle: false, noInlineWake: this.deliveryWorkerMode(target) !== "off" });
|
|
1666
1666
|
}
|
|
1667
1667
|
else {
|
|
@@ -2316,14 +2316,14 @@ export class FleetManager {
|
|
|
2316
2316
|
// "not a beta" and sent a beta install to @latest. #1450 C5: the INSTALLED agend, verified, by absolute path.
|
|
2317
2317
|
const installed = await resolveInstalledAgend();
|
|
2318
2318
|
if (!installed.ok) {
|
|
2319
|
-
this.failUpdateProgress(
|
|
2319
|
+
this.failUpdateProgress(`${t("update.failure.shell")} ${t("update.failure.installed", installed.reason)}`);
|
|
2320
2320
|
return;
|
|
2321
2321
|
}
|
|
2322
2322
|
const origin = `slash /update by ${adapterId}:${data.userId}`;
|
|
2323
2323
|
recordInternalRequest(this.dataDir, "update", origin);
|
|
2324
2324
|
const launch = await resolveUpdateLaunch(installed.agend);
|
|
2325
2325
|
if (!launch.ok) {
|
|
2326
|
-
this.failUpdateProgress(
|
|
2326
|
+
this.failUpdateProgress(`${t("update.failure.shell")} ${t("update.failure.independent", launch.reason)}`);
|
|
2327
2327
|
return;
|
|
2328
2328
|
}
|
|
2329
2329
|
if (this.fleetAdminGate(data.userId, adapterId) !== "ok" || this.shuttingDown) {
|
|
@@ -5398,13 +5398,12 @@ export class FleetManager {
|
|
|
5398
5398
|
const adapter = owner.binding;
|
|
5399
5399
|
const status = this.getPublicWebStatus();
|
|
5400
5400
|
const publicAllowed = publicLinkSettings(this.fleetConfig?.web).allowed;
|
|
5401
|
-
|
|
5402
|
-
const menuText = this.topicCommands.
|
|
5403
|
-
+ (publicAllowed ? "\n
|
|
5404
|
-
+ "\n" + t("dashboard.public_status", status.state, status.remainingSeconds ?? 0)
|
|
5405
|
-
|
|
5406
|
-
|
|
5407
|
-
const choices = [{ action: "local", label: t("dashboard.local") },
|
|
5401
|
+
// Show the action before any link exists. TG's Start instructions belong to confirmed DM refusal below.
|
|
5402
|
+
const menuText = this.topicCommands.getDashboardMenuText()
|
|
5403
|
+
+ (publicAllowed ? "\n" + t("dashboard.public_risk") : "")
|
|
5404
|
+
+ (status.state !== "closed" ? "\n" + t("dashboard.public_status", status.state, status.remainingSeconds ?? 0)
|
|
5405
|
+
+ (status.expiresAt ? t("dashboard.public_until", formatFleetTime(status.expiresAt)) : "") : "");
|
|
5406
|
+
const choices = [{ action: "local", label: t("dashboard.local_signin") },
|
|
5408
5407
|
...(publicLinkSettings(this.fleetConfig?.web).allowed ? [{ action: "public", label: t("dashboard.public_open") }] : []),
|
|
5409
5408
|
...(status.state !== "closed" ? [{ action: "close", label: t("dashboard.public_close") }] : [])];
|
|
5410
5409
|
const posted = await this.postNonceButtonPrompt({
|
|
@@ -5480,9 +5479,11 @@ export class FleetManager {
|
|
|
5480
5479
|
return false;
|
|
5481
5480
|
this.initializeWebSessions();
|
|
5482
5481
|
const issued = this.webLoginCodes.issue({ epoch: tokenEpoch(token), audience: exposureId, owner });
|
|
5483
|
-
//
|
|
5484
|
-
const
|
|
5485
|
-
|
|
5482
|
+
// Only a public link has a link expiry; the code's five-minute lifetime applies to either packet.
|
|
5483
|
+
const minutes = Math.round(LOGIN_CODE_TTL_MS / 60_000);
|
|
5484
|
+
const text = expiresAt !== undefined
|
|
5485
|
+
? t("dashboard.private_public", url, issued.display, minutes, formatFleetTime(expiresAt))
|
|
5486
|
+
: t("dashboard.private_local", url, issued.display, minutes);
|
|
5486
5487
|
const deadline = performance.now() + 10_000;
|
|
5487
5488
|
const direct = owner.binding;
|
|
5488
5489
|
// The route the sign-in message took: the code-only follow-up takes the same one (#1586).
|
|
@@ -5671,7 +5672,6 @@ export class FleetManager {
|
|
|
5671
5672
|
messageId,
|
|
5672
5673
|
});
|
|
5673
5674
|
this.lastUpdateProgressText = null;
|
|
5674
|
-
this.updateCompletionTipText = null;
|
|
5675
5675
|
this.startUpdateProgressMonitor(adapter);
|
|
5676
5676
|
}
|
|
5677
5677
|
/** Persist the public response, wait for idle, then start the canonical service restart. */
|
|
@@ -5702,7 +5702,6 @@ export class FleetManager {
|
|
|
5702
5702
|
return false;
|
|
5703
5703
|
}
|
|
5704
5704
|
this.lastUpdateProgressText = null;
|
|
5705
|
-
this.updateCompletionTipText = null;
|
|
5706
5705
|
this.startUpdateProgressMonitor(adapter);
|
|
5707
5706
|
await this.waitForFullRestartIdleGrace();
|
|
5708
5707
|
// An update can begin while the idle wait yields. Never launch a second
|
|
@@ -5942,17 +5941,8 @@ export class FleetManager {
|
|
|
5942
5941
|
const adapter = this.adapters.get(target.adapterId) ?? (initialAdapter?.id === target.adapterId ? initialAdapter : undefined);
|
|
5943
5942
|
if (!adapter)
|
|
5944
5943
|
return;
|
|
5945
|
-
|
|
5946
|
-
|
|
5947
|
-
// reach RestartProgress.finish(). Append the same optional tip here.
|
|
5948
|
-
if (marker.progress.stage === "complete" && this.tipsEnabled()) {
|
|
5949
|
-
if (this.updateCompletionTipText === null) {
|
|
5950
|
-
const tip = this.pickAvailableTip();
|
|
5951
|
-
this.updateCompletionTipText = tip ? this.formatTip(tip) : "";
|
|
5952
|
-
}
|
|
5953
|
-
if (this.updateCompletionTipText)
|
|
5954
|
-
text += `\n\n${this.updateCompletionTipText}`;
|
|
5955
|
-
}
|
|
5944
|
+
// #1854: no tip on an update's completion (either path); tips come on their own schedule and from /tips.
|
|
5945
|
+
const text = formatUpdateProgress(marker);
|
|
5956
5946
|
if (text === this.lastUpdateProgressText)
|
|
5957
5947
|
return;
|
|
5958
5948
|
this.updateProgressEditRunning = true;
|
|
@@ -6456,12 +6446,6 @@ export class FleetManager {
|
|
|
6456
6446
|
pausedNames,
|
|
6457
6447
|
failedNames,
|
|
6458
6448
|
backgroundWorkEndedNames,
|
|
6459
|
-
tipText: pendingProgressOperation === "update" && this.tipsEnabled()
|
|
6460
|
-
? (() => {
|
|
6461
|
-
const tip = this.pickAvailableTip();
|
|
6462
|
-
return tip ? this.formatTip(tip) : undefined;
|
|
6463
|
-
})()
|
|
6464
|
-
: undefined,
|
|
6465
6449
|
...(cleanupOutcome && "render" in cleanupOutcome
|
|
6466
6450
|
? { warningText: cleanupOutcome.render.warning, warningCommand: cleanupOutcome.render.cleanupCommand }
|
|
6467
6451
|
: {}),
|
|
@@ -8462,7 +8446,7 @@ export class FleetManager {
|
|
|
8462
8446
|
if (!claimNotice(path, WEB_CHAT_NOTICE, adapterId))
|
|
8463
8447
|
continue;
|
|
8464
8448
|
try {
|
|
8465
|
-
await world.adapter.sendText(target.chatId, t("upgrade.web_chat"
|
|
8449
|
+
await world.adapter.sendText(target.chatId, t("upgrade.web_chat"), target.opts);
|
|
8466
8450
|
this.logger.info({ adapterId, notice: WEB_CHAT_NOTICE }, "Announced web chat in General");
|
|
8467
8451
|
}
|
|
8468
8452
|
catch (err) {
|
|
@@ -10448,10 +10432,12 @@ export class FleetManager {
|
|
|
10448
10432
|
return this.webImageCaches[kind];
|
|
10449
10433
|
}
|
|
10450
10434
|
/**
|
|
10451
|
-
*
|
|
10452
|
-
* whatever an instance still names — #1635 review)
|
|
10435
|
+
* The bots instances and ClassicBot rooms speak through, by connections configured now (a connection removed from
|
|
10436
|
+
* fleet.yaml is nobody's, whatever an instance still names — #1635 review). `own`: instance → its own bot (not the
|
|
10437
|
+
* primary, answering for it alone). `speaking` (#1867): instance → the bot it speaks through — its own, a shared one,
|
|
10438
|
+
* or, with none configured for it, the primary.
|
|
10453
10439
|
*/
|
|
10454
|
-
|
|
10440
|
+
webBots() {
|
|
10455
10441
|
const instances = this.fleetConfig?.instances ?? {};
|
|
10456
10442
|
const channels = this.fleetConfig?.channels ?? (this.fleetConfig?.channel ? [this.fleetConfig.channel] : []);
|
|
10457
10443
|
const configured = new Set(channels.map(ch => ch.id ?? ch.type).filter((id) => typeof id === "string"));
|
|
@@ -10461,8 +10447,17 @@ export class FleetManager {
|
|
|
10461
10447
|
if (!Object.hasOwn(instances, room.instanceName))
|
|
10462
10448
|
assignments.push([room.instanceName, assigned(room.instanceName)]);
|
|
10463
10449
|
}
|
|
10464
|
-
|
|
10450
|
+
const primary = this.getPrimaryAdapterId(), fallback = primary && configured.has(primary) ? primary : undefined;
|
|
10451
|
+
const speaking = new Map();
|
|
10452
|
+
for (const [instance, connection] of assignments) {
|
|
10453
|
+
const c = connection ?? fallback;
|
|
10454
|
+
if (c)
|
|
10455
|
+
speaking.set(instance, c);
|
|
10456
|
+
}
|
|
10457
|
+
return { own: ownBotConnections(primary, assignments), speaking };
|
|
10465
10458
|
}
|
|
10459
|
+
/** instance → the connection that is its own bot (see webBots). */
|
|
10460
|
+
ownBots() { return this.webBots().own; }
|
|
10466
10461
|
/**
|
|
10467
10462
|
* The bot a connection is now: its running adapter and that bot's own user id. Everything cached for an own bot is
|
|
10468
10463
|
* keyed by both, so a bot put in its place (a token replaced under the same connection id) never shows the old one's
|
|
@@ -10505,8 +10500,11 @@ export class FleetManager {
|
|
|
10505
10500
|
},
|
|
10506
10501
|
};
|
|
10507
10502
|
}
|
|
10508
|
-
/**
|
|
10509
|
-
|
|
10503
|
+
/**
|
|
10504
|
+
* One instance's avatar and ring for the status frame. Synchronous: what is cached now; fetches run behind. The bot
|
|
10505
|
+
* is its own, else the one it speaks through (#1867) — one cache entry per bot, so a shared bot is fetched once.
|
|
10506
|
+
*/
|
|
10507
|
+
webIdentityImage(name, displayName, profileAvatar, bots) {
|
|
10510
10508
|
let profileVersion = null;
|
|
10511
10509
|
if (profileAvatar && imageMimeForFile(profileAvatar)) {
|
|
10512
10510
|
try {
|
|
@@ -10514,22 +10512,26 @@ export class FleetManager {
|
|
|
10514
10512
|
}
|
|
10515
10513
|
catch { /* removed */ }
|
|
10516
10514
|
}
|
|
10517
|
-
const
|
|
10515
|
+
const ownConnection = bots.own.get(name), connection = ownConnection ?? bots.speaking.get(name);
|
|
10516
|
+
const owner = connection ? this.botOwner(connection) : null;
|
|
10518
10517
|
const source = connection && owner?.adapter.fetchBotAvatar ? this.botAvatarSource(connection, owner) : null;
|
|
10519
10518
|
const bot = source ? this.webImageCache("avatars").peek(source.key, source.load) : null;
|
|
10520
10519
|
const cfg = this.ownInstanceConfig(name);
|
|
10521
10520
|
const avatar = avatarFor({ name, displayName, profileVersion, bot: bot && connection ? { connection, version: bot.version } : null,
|
|
10522
10521
|
personaEmoji: cfg?.status_emojis?.delivered });
|
|
10523
|
-
// The ring belongs to
|
|
10524
|
-
const accent = !profileVersion && bot &&
|
|
10525
|
-
? this.webAccent(
|
|
10522
|
+
// The ring belongs to an own bot's face: only when that is what is shown (a shared bot's would ring everyone alike).
|
|
10523
|
+
const accent = !profileVersion && bot && ownConnection && owner
|
|
10524
|
+
? this.webAccent(ownConnection, owner, cfg ? (cfg.topic_id == null ? undefined : String(cfg.topic_id)) : this.classicChannels?.getChannelIdByInstance(name))
|
|
10526
10525
|
: null;
|
|
10527
10526
|
return accent ? { avatar, accent } : { avatar };
|
|
10528
10527
|
}
|
|
10529
|
-
/**
|
|
10528
|
+
/**
|
|
10529
|
+
* GET /ui/img/bot|avatar/<key>: what is cached, never a fetch. Only a connection some instance or room speaks
|
|
10530
|
+
* through (#1867), or a known instance's upload.
|
|
10531
|
+
*/
|
|
10530
10532
|
webImage(kind, key) {
|
|
10531
10533
|
if (kind === "bot") {
|
|
10532
|
-
if (![...this.
|
|
10534
|
+
if (![...this.webBots().speaking.values()].includes(key))
|
|
10533
10535
|
return null;
|
|
10534
10536
|
const owner = this.botOwner(key);
|
|
10535
10537
|
return owner ? this.webImageCache("avatars").read(this.botAvatarSource(key, owner).key) : null;
|
|
@@ -14579,7 +14581,7 @@ export class FleetManager {
|
|
|
14579
14581
|
const instanceHangConfig = this.fleetConfig?.instances[instanceName]?.hang_detector;
|
|
14580
14582
|
const configuredMinutes = instanceHangConfig?.timeout_minutes
|
|
14581
14583
|
?? this.fleetConfig?.defaults?.hang_detector?.timeout_minutes
|
|
14582
|
-
?? 15
|
|
14584
|
+
?? DEFAULT_STUCK_TIMEOUT_MS / 60_000; // #1854: the detector's own default (10 min), not a stale 15
|
|
14583
14585
|
const unchangedMinutes = unchangedForMs == null
|
|
14584
14586
|
? configuredMinutes
|
|
14585
14587
|
: Math.max(1, Math.floor(unchangedForMs / 60_000));
|
|
@@ -19889,12 +19891,12 @@ Plus the operational skills (fleet-health, instance-lifecycle, scheduling, sessi
|
|
|
19889
19891
|
const classicRooms = new Map((this.classicChannels?.getAll() ?? []).map(ch => [ch.instanceName, ch]));
|
|
19890
19892
|
const profiles = profileIdentities(this.dataDir);
|
|
19891
19893
|
// #1630: decorative — whatever goes wrong deciding an avatar never costs the frame (every instance gets its first character).
|
|
19892
|
-
let
|
|
19894
|
+
let bots = { own: new Map(), speaking: new Map() };
|
|
19893
19895
|
try {
|
|
19894
|
-
|
|
19896
|
+
bots = this.webBots();
|
|
19895
19897
|
}
|
|
19896
19898
|
catch (err) {
|
|
19897
|
-
this.logger.debug({ err }, "
|
|
19899
|
+
this.logger.debug({ err }, "bots unreadable (getUiStatus)");
|
|
19898
19900
|
}
|
|
19899
19901
|
const instances = names.map(name => {
|
|
19900
19902
|
const statusFile = join(this.getInstanceDir(name), "statusline.json");
|
|
@@ -19935,7 +19937,7 @@ Plus the operational skills (fleet-health, instance-lifecycle, scheduling, sessi
|
|
|
19935
19937
|
const identity = resolveInstanceIdentity({ cfg: this.fleetConfig?.instances[name], classic: classicRooms.get(name), profile: profiles.get(name) });
|
|
19936
19938
|
let image;
|
|
19937
19939
|
try {
|
|
19938
|
-
image = this.webIdentityImage(name, identity.display_name, profiles.get(name)?.avatar_path,
|
|
19940
|
+
image = this.webIdentityImage(name, identity.display_name, profiles.get(name)?.avatar_path, bots);
|
|
19939
19941
|
}
|
|
19940
19942
|
catch (err) {
|
|
19941
19943
|
this.logger.debug({ err, name }, "avatar unreadable (getUiStatus)");
|