@songsid/agend 2.3.4-beta.9 → 2.3.4
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/auth-api.js +5 -0
- package/dist/auth-api.js.map +1 -1
- package/dist/backend/codex-metadata.d.ts +14 -0
- package/dist/backend/codex-metadata.js +45 -0
- package/dist/backend/codex-metadata.js.map +1 -1
- package/dist/backend/codex-speed.d.ts +14 -0
- package/dist/backend/codex-speed.js +35 -0
- package/dist/backend/codex-speed.js.map +1 -0
- package/dist/backend/codex.js +9 -2
- package/dist/backend/codex.js.map +1 -1
- package/dist/backend/kiro.js +11 -1
- package/dist/backend/kiro.js.map +1 -1
- package/dist/cache-ledger.d.ts +10 -0
- package/dist/cache-ledger.js +49 -12
- package/dist/cache-ledger.js.map +1 -1
- package/dist/channel/adapters/telegram.d.ts +51 -0
- package/dist/channel/adapters/telegram.js +231 -14
- package/dist/channel/adapters/telegram.js.map +1 -1
- package/dist/channel/types.d.ts +2 -0
- package/dist/config-validator.js +5 -0
- package/dist/config-validator.js.map +1 -1
- package/dist/fleet-manager.d.ts +11 -0
- package/dist/fleet-manager.js +90 -10
- package/dist/fleet-manager.js.map +1 -1
- package/dist/general-knowledge/skills/concepts/SKILL.md +3 -0
- package/dist/general-knowledge/skills/web-dashboard/SKILL.md +7 -2
- package/dist/instance-config-impact.js +2 -0
- package/dist/instance-config-impact.js.map +1 -1
- package/dist/locale.js +10 -0
- package/dist/locale.js.map +1 -1
- package/dist/log-service.d.ts +28 -0
- package/dist/log-service.js +29 -0
- package/dist/log-service.js.map +1 -1
- package/dist/logger.d.ts +12 -0
- package/dist/logger.js +43 -1
- package/dist/logger.js.map +1 -1
- package/dist/missed-offline.d.ts +25 -0
- package/dist/missed-offline.js +79 -0
- package/dist/missed-offline.js.map +1 -0
- package/dist/needs-you-hub.d.ts +6 -1
- package/dist/needs-you-hub.js +30 -7
- package/dist/needs-you-hub.js.map +1 -1
- package/dist/needs-you.d.ts +16 -2
- package/dist/needs-you.js +9 -1
- package/dist/needs-you.js.map +1 -1
- package/dist/settings-api.js +10 -0
- package/dist/settings-api.js.map +1 -1
- package/dist/settings-change.js +16 -1
- package/dist/settings-change.js.map +1 -1
- package/dist/settings-instance-patch.js +27 -0
- package/dist/settings-instance-patch.js.map +1 -1
- package/dist/ui/chat-md-strings.js +9 -0
- package/dist/ui/chat-thread.js +53 -3
- package/dist/ui/panel-chat.js +3 -2
- package/dist/ui/panel-needs.js +13 -5
- package/dist/ui/preview-panel.js +78 -2
- package/dist/ui/settings-codex-copy.js +19 -0
- package/dist/ui/settings-dialogs.js +8 -0
- package/dist/ui/settings-model.js +16 -2
- package/dist/ui/shared/app-i18n.js +2 -2
- package/dist/ui/shared/app.css +4 -0
- package/dist/ui/shared/panel-view.js +77 -4
- package/dist/ui/shared/view-history.css +17 -0
- package/dist/ui/shared/view-history.js +438 -0
- package/dist/usage-rollup.d.ts +2 -0
- package/dist/usage-rollup.js +9 -6
- package/dist/usage-rollup.js.map +1 -1
- package/dist/view-api.d.ts +16 -0
- package/dist/view-api.js +100 -16
- package/dist/view-api.js.map +1 -1
- package/dist/view-history.d.ts +84 -0
- package/dist/view-history.js +116 -0
- package/dist/view-history.js.map +1 -0
- package/launcher/private-home.cjs +1 -1
- package/package.json +1 -1
package/dist/fleet-manager.d.ts
CHANGED
|
@@ -62,6 +62,7 @@ export declare function applyTaskListCap<T extends {
|
|
|
62
62
|
} | T[];
|
|
63
63
|
import { type PublicPreviewForUi } from "./web-api.js";
|
|
64
64
|
import { type LogAnswer, type LogQuery } from "./log-service.js";
|
|
65
|
+
import { type ViewHistoryAnswer, type ViewHistoryQuery } from "./view-history.js";
|
|
65
66
|
import { WebChatHistory, type WebChatPost } from "./web-chat-history.js";
|
|
66
67
|
import { type WebEchoCopy } from "./web-reactions.js";
|
|
67
68
|
import { SeenUsers, type MentionNames, type MentionQuery } from "./web-mentions.js";
|
|
@@ -478,6 +479,7 @@ export declare class FleetManager implements FleetContext, LifecycleContext, Arc
|
|
|
478
479
|
private kiroMigrationRuns;
|
|
479
480
|
/** #1386 "Needs you": the list, its live chat messages and Acknowledge. Started with the fleet (finishStartup). */
|
|
480
481
|
private needsYou;
|
|
482
|
+
private missedOfflineStore;
|
|
481
483
|
private configHistory;
|
|
482
484
|
private configHistoryTimer;
|
|
483
485
|
private loadedFleetSource;
|
|
@@ -1221,6 +1223,11 @@ export declare class FleetManager implements FleetContext, LifecycleContext, Arc
|
|
|
1221
1223
|
/** Board 003648ac: a web /compact followed to its end, from the transcript the Log reads (none: nothing to follow). */
|
|
1222
1224
|
private compactWatchService;
|
|
1223
1225
|
private get compactWatch();
|
|
1226
|
+
/**
|
|
1227
|
+
* Claude history in the View: an instance's earlier conversation for its View, from the transcript the Log reads —
|
|
1228
|
+
* the View's route applied its own access rules first (view-api.ts); the Log's switch plays no part.
|
|
1229
|
+
*/
|
|
1230
|
+
viewHistory(name: string, q: ViewHistoryQuery): Promise<ViewHistoryAnswer | null>;
|
|
1224
1231
|
/** #1218: GET /ui/steps — an instance's steps, read on demand (null: no such instance). */
|
|
1225
1232
|
logSteps(name: string, q: LogQuery): Promise<LogAnswer | null>;
|
|
1226
1233
|
/**
|
|
@@ -2307,6 +2314,8 @@ export declare class FleetManager implements FleetContext, LifecycleContext, Arc
|
|
|
2307
2314
|
* copies retain their permissive handling when that identity is unknown.
|
|
2308
2315
|
*/
|
|
2309
2316
|
private isOwnerCommandCopy;
|
|
2317
|
+
/** File a Telegram update that was too old to inject; Needs you lists it until Acknowledge. */
|
|
2318
|
+
private recordMissedOffline;
|
|
2310
2319
|
/**
|
|
2311
2320
|
* #1085: coincident topic numbers must not route across Telegram groups.
|
|
2312
2321
|
*/
|
|
@@ -3549,6 +3558,8 @@ export declare class FleetManager implements FleetContext, LifecycleContext, Arc
|
|
|
3549
3558
|
*/
|
|
3550
3559
|
/** Configured threshold before elapsed time appears, in ms. */
|
|
3551
3560
|
progressMinElapsedMs(): number;
|
|
3561
|
+
/** M-2391: when the instance's live (not retiring) bubble started — the current turn's start — or undefined. */
|
|
3562
|
+
private liveButtonStart;
|
|
3552
3563
|
private startProgressTicker;
|
|
3553
3564
|
/**
|
|
3554
3565
|
* After a reply: give the instance REPLY_RETIRE_GRACE_MS to resume working; if
|
package/dist/fleet-manager.js
CHANGED
|
@@ -92,6 +92,7 @@ import { formatFleetTime } from "./tz-utils.js";
|
|
|
92
92
|
import { createAdapter } from "./channel/factory.js";
|
|
93
93
|
import { isWebChannelEcho, WEB_ECHO_PREFIX } from "./web-channel-echo.js";
|
|
94
94
|
import { TelegramAdapter } from "./channel/adapters/telegram.js";
|
|
95
|
+
import { MissedOfflineStore } from "./missed-offline.js";
|
|
95
96
|
import { createBackend } from "./backend/factory.js";
|
|
96
97
|
import { readEffortMetadata } from "./backend/effort-metadata.js";
|
|
97
98
|
import { codexEffort, flagEffort } from "./backend/launch-effort.js";
|
|
@@ -171,6 +172,7 @@ export function applyTaskListCap(tasks, filterAssignee, filterStatus) {
|
|
|
171
172
|
}
|
|
172
173
|
import { handleWebRequest, webPeerOf, broadcastSseEvent, broadcastToGuests, SSE_HEARTBEAT_MS } from "./web-api.js";
|
|
173
174
|
import { LogService } from "./log-service.js";
|
|
175
|
+
import { viewHistory } from "./view-history.js";
|
|
174
176
|
import { WebChatHistory, WEB_CHAT_TEXT_MAX, isWebMessageId, newWebMessageId, webChatFrom } from "./web-chat-history.js";
|
|
175
177
|
import { WEB_ECHO_COPIES_MAX, WEB_MIRROR_TIMEOUT_MS, webReactionEmoji, webReactionProblem } from "./web-reactions.js";
|
|
176
178
|
import { WebChatDiskStore } from "./web-chat-store.js";
|
|
@@ -467,6 +469,8 @@ const INSTALL_TIMEOUT_MS = 10 * 60 * 1000;
|
|
|
467
469
|
* while anything real shows signs of life well before the old two minutes.
|
|
468
470
|
*/
|
|
469
471
|
const PROGRESS_MIN_ELAPSED_MS = 30_000;
|
|
472
|
+
/** M-2391: the threshold tick fires this long after it, never a millisecond before (timers can fire early). */
|
|
473
|
+
const PROGRESS_THRESHOLD_MARGIN_MS = 50;
|
|
470
474
|
/** How much of a tool summary the progress line will show before eliding. */
|
|
471
475
|
const PROGRESS_ACTIVITY_MAX_CHARS = 48;
|
|
472
476
|
/**
|
|
@@ -926,6 +930,7 @@ export class FleetManager {
|
|
|
926
930
|
kiroMigrationRuns = new Map();
|
|
927
931
|
/** #1386 "Needs you": the list, its live chat messages and Acknowledge. Started with the fleet (finishStartup). */
|
|
928
932
|
needsYou = null;
|
|
933
|
+
missedOfflineStore = null;
|
|
929
934
|
configHistory = null;
|
|
930
935
|
configHistoryTimer = null;
|
|
931
936
|
loadedFleetSource = null;
|
|
@@ -2205,6 +2210,7 @@ export class FleetManager {
|
|
|
2205
2210
|
this.topicCommands = new TopicCommands(this);
|
|
2206
2211
|
this.topicArchiver = new TopicArchiver(this);
|
|
2207
2212
|
this.statuslineWatcher = new StatuslineWatcher(this);
|
|
2213
|
+
this.missedOfflineStore = new MissedOfflineStore(this.dataDir);
|
|
2208
2214
|
}
|
|
2209
2215
|
/** #1266: a reply's buttons — the store (reply-buttons.db) and what a click does. Created on first use. */
|
|
2210
2216
|
replyButtonsCtl = null;
|
|
@@ -4095,6 +4101,13 @@ export class FleetManager {
|
|
|
4095
4101
|
changed: () => this.emitSseEvent("status", this.getUiStatus()),
|
|
4096
4102
|
});
|
|
4097
4103
|
}
|
|
4104
|
+
/**
|
|
4105
|
+
* Claude history in the View: an instance's earlier conversation for its View, from the transcript the Log reads —
|
|
4106
|
+
* the View's route applied its own access rules first (view-api.ts); the Log's switch plays no part.
|
|
4107
|
+
*/
|
|
4108
|
+
viewHistory(name, q) {
|
|
4109
|
+
return viewHistory((n, rq) => this.log.readBack(n, rq), name, q);
|
|
4110
|
+
}
|
|
4098
4111
|
/** #1218: GET /ui/steps — an instance's steps, read on demand (null: no such instance). */
|
|
4099
4112
|
logSteps(name, q) { return this.log.steps(name, q); }
|
|
4100
4113
|
/**
|
|
@@ -9446,6 +9459,11 @@ export class FleetManager {
|
|
|
9446
9459
|
adapter.on("callback_query", safeHandler(async (data) => {
|
|
9447
9460
|
await this.receiveAdapterCallback(data, adapterId, adapter, isCurrentAdapter);
|
|
9448
9461
|
}, this.logger, "adapter.callback_query"));
|
|
9462
|
+
adapter.on("missed_offline", (ev) => {
|
|
9463
|
+
if (!isCurrentAdapter())
|
|
9464
|
+
return;
|
|
9465
|
+
this.recordMissedOffline(ev);
|
|
9466
|
+
});
|
|
9449
9467
|
this.bindTopicClosedHandler(adapter, adapterId, "adapter.topic_closed");
|
|
9450
9468
|
// Handle classic bot slash commands (/start, /stop, /chat, /compact, /save, /load)
|
|
9451
9469
|
adapter.on("slash_command", safeHandler(async (data) => {
|
|
@@ -9599,6 +9617,11 @@ export class FleetManager {
|
|
|
9599
9617
|
adapter.on("callback_query", safeHandler(async (data) => {
|
|
9600
9618
|
await this.receiveAdapterCallback(data, adapterId, adapter, isCurrentAdapter);
|
|
9601
9619
|
}, this.logger, `adapter[${adapterId}].callback_query`));
|
|
9620
|
+
adapter.on("missed_offline", (ev) => {
|
|
9621
|
+
if (!isCurrentAdapter())
|
|
9622
|
+
return;
|
|
9623
|
+
this.recordMissedOffline(ev);
|
|
9624
|
+
});
|
|
9602
9625
|
this.bindTopicClosedHandler(adapter, adapterId, `adapter[${adapterId}].topic_closed`);
|
|
9603
9626
|
// Slash commands: classic bot + admin commands
|
|
9604
9627
|
adapter.on("slash_command", safeHandler(async (data) => {
|
|
@@ -10335,6 +10358,34 @@ export class FleetManager {
|
|
|
10335
10358
|
}
|
|
10336
10359
|
return true;
|
|
10337
10360
|
}
|
|
10361
|
+
/** File a Telegram update that was too old to inject; Needs you lists it until Acknowledge. */
|
|
10362
|
+
recordMissedOffline(ev) {
|
|
10363
|
+
if (!this.missedOfflineStore)
|
|
10364
|
+
this.missedOfflineStore = new MissedOfflineStore(this.dataDir);
|
|
10365
|
+
const stub = {
|
|
10366
|
+
source: "telegram", adapterId: ev.adapterId, chatId: ev.chatId, threadId: ev.threadId,
|
|
10367
|
+
messageId: ev.messageId, userId: ev.userId, username: ev.username, text: ev.preview,
|
|
10368
|
+
timestamp: ev.timestamp, isBotMessage: false,
|
|
10369
|
+
};
|
|
10370
|
+
const threadId = this.inboundRouteThreadId(stub);
|
|
10371
|
+
const target = threadId ? this.resolveInboundTarget(stub, threadId) : undefined;
|
|
10372
|
+
let instance = target?.name ?? "";
|
|
10373
|
+
if (!instance) {
|
|
10374
|
+
instance = Object.entries(this.fleetConfig?.instances ?? {}).find(([name, cfg]) => cfg.general_topic && this.getInstanceAdapterId(name) === ev.adapterId)?.[0] ?? "";
|
|
10375
|
+
}
|
|
10376
|
+
const place = [ev.chatTitle, ev.threadId ? `#${ev.threadId}` : ""].filter(Boolean).join(" · ") || ev.chatId;
|
|
10377
|
+
this.missedOfflineStore.add({
|
|
10378
|
+
id: `missed:${ev.adapterId}:${ev.updateId}`,
|
|
10379
|
+
adapterId: ev.adapterId,
|
|
10380
|
+
instance,
|
|
10381
|
+
username: ev.username,
|
|
10382
|
+
place,
|
|
10383
|
+
preview: ev.preview,
|
|
10384
|
+
since: ev.timestamp.getTime(),
|
|
10385
|
+
});
|
|
10386
|
+
this.logger.info({ adapterId: ev.adapterId, updateId: ev.updateId, instance, chatId: ev.chatId, threadId: ev.threadId }, "Telegram message missed while AgEnD was offline — filed for Needs you");
|
|
10387
|
+
this.needsYou?.poke();
|
|
10388
|
+
}
|
|
10338
10389
|
/**
|
|
10339
10390
|
* #1085: coincident topic numbers must not route across Telegram groups.
|
|
10340
10391
|
*/
|
|
@@ -15539,6 +15590,10 @@ export class FleetManager {
|
|
|
15539
15590
|
throw new Error("the delivery outbox is not open");
|
|
15540
15591
|
return this.deliveryOutbox.acknowledge(deliveryId, by);
|
|
15541
15592
|
},
|
|
15593
|
+
missedOffline: () => (this.missedOfflineStore?.list(Date.now()) ?? []).map(m => ({
|
|
15594
|
+
id: m.id, instance: m.instance, owner: m.adapterId, username: m.username, place: m.place, preview: m.preview, since: m.since,
|
|
15595
|
+
})),
|
|
15596
|
+
acknowledgeMissed: (id, by) => this.missedOfflineStore?.acknowledge(id, by) ?? false,
|
|
15542
15597
|
tasks: () => this.needsYouTaskItems(),
|
|
15543
15598
|
backendSignIns: () => this.needsYouBackendSignIns(),
|
|
15544
15599
|
configIssues: () => (this.configHistory?.currentIssues() ?? []).map(issue => ({
|
|
@@ -17189,7 +17244,14 @@ export class FleetManager {
|
|
|
17189
17244
|
return;
|
|
17190
17245
|
}
|
|
17191
17246
|
const publication = this.beginCancelButtonPublication(instanceName, correlationId);
|
|
17192
|
-
|
|
17247
|
+
// M-2391: a re-post below a reply (preserveProgress) continues the same turn — its elapsed time continues from
|
|
17248
|
+
// the live bubble's start, as its tool list does. Restarting it at 0 meant an agent replying more often than the
|
|
17249
|
+
// threshold never showed elapsed time at all. A fresh turn (no preserve) starts at 0 as before.
|
|
17250
|
+
const carriedStart = preserveProgress ? this.liveButtonStart(instanceName) : undefined;
|
|
17251
|
+
const carriedMs = carriedStart !== undefined ? Math.max(0, Date.now() - carriedStart) : 0;
|
|
17252
|
+
const initialProgressText = carriedStart !== undefined && carriedMs >= this.progressMinElapsedMs()
|
|
17253
|
+
? FleetManager.progressText(carriedMs, null, this.progressMinElapsedMs(), this.progressPrefixFor(instanceName, carriedMs))
|
|
17254
|
+
: FleetManager.progressText(0, null, 1, this.progressPrefixFor(instanceName, 0, 1));
|
|
17193
17255
|
try {
|
|
17194
17256
|
const sent = await adapter.notifyAlert(chatId, {
|
|
17195
17257
|
type: "cancel",
|
|
@@ -17212,7 +17274,7 @@ export class FleetManager {
|
|
|
17212
17274
|
// Elapsed time is measured from when this button was posted — i.e. from
|
|
17213
17275
|
// when the work was handed over — not from the pane's working transition,
|
|
17214
17276
|
// which resets if the CLI blips idle mid-turn.
|
|
17215
|
-
startedAt: Date.now(),
|
|
17277
|
+
startedAt: carriedStart ?? Date.now(),
|
|
17216
17278
|
// Matches the text notifyAlert just posted, so the first 60s tick does
|
|
17217
17279
|
// not re-edit identical text — which put a "(edited)" mark on Discord
|
|
17218
17280
|
// with nothing visibly changed.
|
|
@@ -17463,6 +17525,12 @@ export class FleetManager {
|
|
|
17463
17525
|
}
|
|
17464
17526
|
return PROGRESS_MIN_ELAPSED_MS;
|
|
17465
17527
|
}
|
|
17528
|
+
/** M-2391: when the instance's live (not retiring) bubble started — the current turn's start — or undefined. */
|
|
17529
|
+
liveButtonStart(instanceName) {
|
|
17530
|
+
const starts = [...this.cancelButtons.values()].filter((e) => e.instanceName === instanceName && !e.retiring && typeof e.startedAt === "number")
|
|
17531
|
+
.map((e) => e.startedAt);
|
|
17532
|
+
return starts.length ? Math.min(...starts) : undefined;
|
|
17533
|
+
}
|
|
17466
17534
|
startProgressTicker(entry) {
|
|
17467
17535
|
const tick = () => this.refreshBubble(entry);
|
|
17468
17536
|
entry.progressTimer = setInterval(tick, PROGRESS_UPDATE_INTERVAL_MS);
|
|
@@ -17472,7 +17540,9 @@ export class FleetManager {
|
|
|
17472
17540
|
// one additional edit per turn that lives past the threshold.
|
|
17473
17541
|
const firstAt = this.progressMinElapsedMs() - (Date.now() - (entry.startedAt ?? Date.now()));
|
|
17474
17542
|
if (firstAt > 0 && firstAt < PROGRESS_UPDATE_INTERVAL_MS) {
|
|
17475
|
-
|
|
17543
|
+
// M-2391: a little past the threshold — a timer can fire a millisecond before Date.now() reaches it, which
|
|
17544
|
+
// rendered the unchanged "處理中…" text and skipped the edit until the next 60 s interval.
|
|
17545
|
+
const firstTick = setTimeout(tick, firstAt + PROGRESS_THRESHOLD_MARGIN_MS);
|
|
17476
17546
|
firstTick.unref?.();
|
|
17477
17547
|
}
|
|
17478
17548
|
}
|
|
@@ -21827,6 +21897,22 @@ Plus the operational skills (fleet-health, instance-lifecycle, scheduling, sessi
|
|
|
21827
21897
|
// because we asked it to. Set synchronously — doStopAll runs to its first
|
|
21828
21898
|
// await in the same tick as the signal handler, so no event can slip in.
|
|
21829
21899
|
this.shuttingDown = true;
|
|
21900
|
+
// Stop receive admission before the first await or any instance shutdown; outbound
|
|
21901
|
+
// adapters remain available below to retire notices and pending prompts.
|
|
21902
|
+
for (const state of this.adapterState.values()) {
|
|
21903
|
+
if (state.retryTimer) {
|
|
21904
|
+
clearTimeout(state.retryTimer);
|
|
21905
|
+
state.retryTimer = undefined;
|
|
21906
|
+
}
|
|
21907
|
+
}
|
|
21908
|
+
const inboundStopped = Promise.all([...this.adapters.values()].map(async (adapter) => {
|
|
21909
|
+
try {
|
|
21910
|
+
await adapter.stopReceiving?.();
|
|
21911
|
+
}
|
|
21912
|
+
catch (err) {
|
|
21913
|
+
this.logger.warn({ adapterId: adapter.id, err }, "Adapter receive stop failed; inbound remains fenced");
|
|
21914
|
+
}
|
|
21915
|
+
}));
|
|
21830
21916
|
this.workingRecovery?.reset();
|
|
21831
21917
|
if (this.workingRecoveryTimer)
|
|
21832
21918
|
clearInterval(this.workingRecoveryTimer);
|
|
@@ -21886,6 +21972,7 @@ Plus the operational skills (fleet-health, instance-lifecycle, scheduling, sessi
|
|
|
21886
21972
|
// A login/install window is a dedicated tmux server with its own TTL
|
|
21887
21973
|
// timer and HTTP listener living in THIS process: without an explicit
|
|
21888
21974
|
// shutdown it would outlive us as an owner-less login CLI (sol B3).
|
|
21975
|
+
await inboundStopped;
|
|
21889
21976
|
await publicStopped;
|
|
21890
21977
|
await sharesStopped?.catch(() => { });
|
|
21891
21978
|
await profileStopped;
|
|
@@ -21896,13 +21983,6 @@ Plus the operational skills (fleet-health, instance-lifecycle, scheduling, sessi
|
|
|
21896
21983
|
await this.cpuProfileControl?.close();
|
|
21897
21984
|
this.cpuProfileControl = null;
|
|
21898
21985
|
await this.shutdownLoginWindows();
|
|
21899
|
-
// Cancel adapter retry timers
|
|
21900
|
-
for (const state of this.adapterState.values()) {
|
|
21901
|
-
if (state.retryTimer) {
|
|
21902
|
-
clearTimeout(state.retryTimer);
|
|
21903
|
-
state.retryTimer = undefined;
|
|
21904
|
-
}
|
|
21905
|
-
}
|
|
21906
21986
|
this.clearStatuslineWatchers();
|
|
21907
21987
|
this.costGuard?.stop();
|
|
21908
21988
|
this.dailySummary?.stop();
|