@songsid/agend 2.3.2 → 2.3.3-beta.2

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 (136) hide show
  1. package/dist/agent-cli-instructions.md +2 -2
  2. package/dist/agent-whats-new.d.ts +21 -0
  3. package/dist/agent-whats-new.js +52 -23
  4. package/dist/agent-whats-new.js.map +1 -1
  5. package/dist/authority/authority-state.js +1 -1
  6. package/dist/authority/authority-state.js.map +1 -1
  7. package/dist/authority/web-authority.d.ts +9 -4
  8. package/dist/authority/web-authority.js +10 -5
  9. package/dist/authority/web-authority.js.map +1 -1
  10. package/dist/backend/claude-code.d.ts +13 -1
  11. package/dist/backend/claude-code.js +20 -1
  12. package/dist/backend/claude-code.js.map +1 -1
  13. package/dist/backend/codex-session-lookup.d.ts +16 -3
  14. package/dist/backend/codex-session-lookup.js +45 -11
  15. package/dist/backend/codex-session-lookup.js.map +1 -1
  16. package/dist/backend/kiro-reconcile-store.js +8 -1
  17. package/dist/backend/kiro-reconcile-store.js.map +1 -1
  18. package/dist/backend/kiro.d.ts +0 -5
  19. package/dist/backend/kiro.js +0 -10
  20. package/dist/backend/kiro.js.map +1 -1
  21. package/dist/backend/types.d.ts +7 -4
  22. package/dist/backend/types.js.map +1 -1
  23. package/dist/cli.js +18 -3
  24. package/dist/cli.js.map +1 -1
  25. package/dist/config-validator.js +4 -5
  26. package/dist/config-validator.js.map +1 -1
  27. package/dist/config.js +4 -2
  28. package/dist/config.js.map +1 -1
  29. package/dist/cross-instance-envelope.d.ts +10 -5
  30. package/dist/cross-instance-envelope.js +20 -17
  31. package/dist/cross-instance-envelope.js.map +1 -1
  32. package/dist/daemon.d.ts +90 -63
  33. package/dist/daemon.js +412 -317
  34. package/dist/daemon.js.map +1 -1
  35. package/dist/daily-summary.d.ts +8 -1
  36. package/dist/daily-summary.js +8 -5
  37. package/dist/daily-summary.js.map +1 -1
  38. package/dist/delivery-outbox.d.ts +31 -22
  39. package/dist/delivery-outbox.js +119 -161
  40. package/dist/delivery-outbox.js.map +1 -1
  41. package/dist/delivery-outbox.test.js +10 -25
  42. package/dist/delivery-outbox.test.js.map +1 -1
  43. package/dist/fleet-level-config.js +1 -1
  44. package/dist/fleet-level-config.js.map +1 -1
  45. package/dist/fleet-manager.d.ts +4 -21
  46. package/dist/fleet-manager.js +38 -159
  47. package/dist/fleet-manager.js.map +1 -1
  48. package/dist/fleet-service-owner.d.ts +11 -0
  49. package/dist/fleet-service-owner.js +3 -0
  50. package/dist/fleet-service-owner.js.map +1 -0
  51. package/dist/general-knowledge/skills/delegation-playbook/SKILL.md +1 -1
  52. package/dist/general-knowledge/skills/fleet-restart/SKILL.md +1 -1
  53. package/dist/general-knowledge/skills/session-management/SKILL.md +1 -1
  54. package/dist/general-knowledge/skills/web-dashboard/SKILL.canvas-worker-off.md +4 -5
  55. package/dist/general-knowledge/skills/web-dashboard/SKILL.md +4 -5
  56. package/dist/instance-lifecycle.js +23 -5
  57. package/dist/instance-lifecycle.js.map +1 -1
  58. package/dist/instructions.js +6 -7
  59. package/dist/instructions.js.map +1 -1
  60. package/dist/kiro-reconcile.js +3 -3
  61. package/dist/kiro-reconcile.js.map +1 -1
  62. package/dist/locale.js +8 -52
  63. package/dist/locale.js.map +1 -1
  64. package/dist/log-service.js +1 -1
  65. package/dist/log-service.js.map +1 -1
  66. package/dist/needs-you-hub.js +4 -1
  67. package/dist/needs-you-hub.js.map +1 -1
  68. package/dist/needs-you-live.d.ts +3 -1
  69. package/dist/needs-you-live.js +24 -2
  70. package/dist/needs-you-live.js.map +1 -1
  71. package/dist/needs-you.d.ts +6 -1
  72. package/dist/needs-you.js +4 -0
  73. package/dist/needs-you.js.map +1 -1
  74. package/dist/outbound-handlers.js +1 -1
  75. package/dist/outbound-handlers.js.map +1 -1
  76. package/dist/outbound-schemas.js +1 -1
  77. package/dist/outbound-schemas.js.map +1 -1
  78. package/dist/scheduler/task-board.d.ts +17 -25
  79. package/dist/scheduler/task-board.js +29 -39
  80. package/dist/scheduler/task-board.js.map +1 -1
  81. package/dist/sd-notify.d.ts +13 -14
  82. package/dist/sd-notify.js +62 -28
  83. package/dist/sd-notify.js.map +1 -1
  84. package/dist/settings-api.d.ts +0 -1
  85. package/dist/settings-api.js +1 -14
  86. package/dist/settings-api.js.map +1 -1
  87. package/dist/settings-effect.js +0 -2
  88. package/dist/settings-effect.js.map +1 -1
  89. package/dist/setup-wizard.d.ts +3 -0
  90. package/dist/setup-wizard.js +4 -2
  91. package/dist/setup-wizard.js.map +1 -1
  92. package/dist/task-board-waker.d.ts +40 -1
  93. package/dist/task-board-waker.js +110 -9
  94. package/dist/task-board-waker.js.map +1 -1
  95. package/dist/tmux-control.d.ts +1 -1
  96. package/dist/tmux-control.js +3 -2
  97. package/dist/tmux-control.js.map +1 -1
  98. package/dist/tmux-manager.js +18 -16
  99. package/dist/tmux-manager.js.map +1 -1
  100. package/dist/tmux-read.d.ts +2 -0
  101. package/dist/tmux-read.js +7 -1
  102. package/dist/tmux-read.js.map +1 -1
  103. package/dist/topic-commands.d.ts +2 -0
  104. package/dist/topic-commands.js +2 -1
  105. package/dist/topic-commands.js.map +1 -1
  106. package/dist/transcript-monitor.js +17 -0
  107. package/dist/transcript-monitor.js.map +1 -1
  108. package/dist/types.d.ts +7 -10
  109. package/dist/ui/panel-log.js +2 -2
  110. package/dist/ui/settings-appearance.js +3 -35
  111. package/dist/ui/settings-registry.js +0 -1
  112. package/dist/ui/settings-strings.js +4 -4
  113. package/dist/ui/settings-web-authority.js +4 -3
  114. package/dist/ui/shared/app-i18n.js +2 -2
  115. package/dist/update-check.d.ts +13 -4
  116. package/dist/update-check.js +17 -4
  117. package/dist/update-check.js.map +1 -1
  118. package/dist/web-experimental.d.ts +6 -2
  119. package/dist/web-experimental.js +8 -4
  120. package/dist/web-experimental.js.map +1 -1
  121. package/dist/web-settings-patch.d.ts +0 -1
  122. package/dist/web-settings-patch.js +3 -4
  123. package/dist/web-settings-patch.js.map +1 -1
  124. package/dist/workflow-templates/default.md +2 -2
  125. package/dist/working-recovery.d.ts +0 -2
  126. package/dist/working-recovery.js +2 -23
  127. package/dist/working-recovery.js.map +1 -1
  128. package/launcher/agend-install.cjs +7 -1
  129. package/launcher/fleet-service-owner.cjs +138 -0
  130. package/package.json +1 -1
  131. package/dist/task-board-summary.d.ts +0 -101
  132. package/dist/task-board-summary.js +0 -177
  133. package/dist/task-board-summary.js.map +0 -1
  134. package/dist/upgrade-notices.d.ts +0 -17
  135. package/dist/upgrade-notices.js +0 -93
  136. package/dist/upgrade-notices.js.map +0 -1
package/dist/daemon.d.ts CHANGED
@@ -23,34 +23,6 @@ import type { KiroLogLaunch } from "./kiro-log-gate.js";
23
23
  * often; a long silent tool run shows its own busy row on the pane.
24
24
  */
25
25
  export declare const TRANSCRIPT_OPEN_TURN_QUIET_MS: number;
26
- export declare function buildInstructionReloadNotice(binaryName: string, instanceName: string, instanceDir: string, backendSource?: string | null): string;
27
- /**
28
- * Whether this backend has to be told in its pane that its instructions moved.
29
- *
30
- * A backend that re-reads them on resume already received the new ones from the
31
- * resume itself, so the notice is pure interruption. Both places that can send
32
- * it — the warmup paste and the deferred pendingInstructionsNotice — ask through
33
- * here, so the two cannot drift apart again: the warmup path used to omit this
34
- * check entirely and told claude-code to reload instructions it had just read.
35
- */
36
- export declare function backendNeedsPaneReloadNotice(backend?: {
37
- instructionsReloadedOnResume?: boolean;
38
- }): boolean;
39
- /**
40
- * What the warmup should do about changed instructions.
41
- *
42
- * `skip` — nothing to say, or this backend learns of the change by itself.
43
- * `defer` — worth saying, but nobody is talking to the instance; say it when a
44
- * real message next arrives rather than provoking an unsolicited reply.
45
- * `paste` — say it now, into a pane that already has a delivery in flight.
46
- */
47
- export declare function warmupNoticeAction(opts: {
48
- warmupNeeded: boolean;
49
- backend?: {
50
- instructionsReloadedOnResume?: boolean;
51
- };
52
- pasteQueueDepth: number;
53
- }): "skip" | "defer" | "paste";
54
26
  export declare const DEFAULT_STUCK_TIMEOUT_MS: number;
55
27
  export declare const DEFAULT_STATE_IDLE_DEBOUNCE_MS = 2000;
56
28
  export declare const DEFAULT_STATE_SAFETY_SWEEP_MS = 60000;
@@ -58,6 +30,14 @@ export declare const DEFAULT_STATE_SAFETY_SWEEP_MS = 60000;
58
30
  export declare const PERIODIC_REDRAW_PROBE_MS = 25;
59
31
  /** Do not turn a streaming Codex turn into one capture-pane per burst. */
60
32
  export declare const STRUCTURED_IDLE_PROBE_MS = 500;
33
+ /** #2770 (ii): how often output may schedule a look for a layout that repaints while idle (CliBackend.periodicRedrawFrom). */
34
+ export declare const PERIODIC_LAYOUT_LOOK_MS = 5000;
35
+ /** #2770: how often a delivery waiting for idle asks again whether it can be handed off instead. */
36
+ export declare const HANDOFF_RECHECK_MS = 1000;
37
+ /** #2770: how often a wait for idle asks its stop condition (a cancel, a hand-off that became possible). */
38
+ export declare const WAIT_STOP_POLL_MS = 250;
39
+ /** #2770: human messages a cancel dropped are told in one notice, this long after the last of them. */
40
+ export declare const CANCELLED_HUMANS_NOTICE_MS = 1000;
61
41
  /**
62
42
  * An instance publishing more than this many execution-state edges inside the
63
43
  * window is flapping; its edges stop being logged one by one (#1116). One
@@ -554,6 +534,8 @@ export declare class Daemon extends EventEmitter {
554
534
  private bootSkippedResume;
555
535
  private recoveryCrashLoopFresh;
556
536
  private recoveryFreshChoice;
537
+ /** The current boot found a crash-loop marker and is attempting resume rather than going fresh immediately. */
538
+ private bootCrashLoopResume;
557
539
  private startupAborted;
558
540
  /** First time the current on-screen blocking dialog was seen (0 = none); drives the parked report. */
559
541
  private dialogParkedSince;
@@ -649,6 +631,10 @@ export declare class Daemon extends EventEmitter {
649
631
  /** Consecutive structural idle captures for a noisy, periodically-redrawing
650
632
  * pane. Two are required before a working -> idle transition. */
651
633
  private instanceStatePeriodicIdleConfirmations;
634
+ /** #2770 (ii): the latest capture showed a layout that repaints while idle (CliBackend.periodicRedrawFrom). */
635
+ private periodicRedrawLayout;
636
+ /** When output last scheduled a look for that layout (monotonic ms), so a busy pane is not captured on every chunk. */
637
+ private periodicLayoutLookAt;
652
638
  /** Recent execution-state edge times, for the flap log limiter (#1116). */
653
639
  private stateEdgeTimes;
654
640
  private stateEdgesNotLogged;
@@ -687,7 +673,6 @@ export declare class Daemon extends EventEmitter {
687
673
  /** Prevent a visible stale XML fragment from being recovered on later turns. */
688
674
  private lastMalformedToolCallSignature;
689
675
  private proxyReplySeq;
690
- private lastReplyDropWarningAt;
691
676
  /**
692
677
  * #1241: an idle edge that has not yet proven the turn ended. Armed instead
693
678
  * of recovering immediately; a steady idle snapshot past confirmAt promotes
@@ -746,6 +731,8 @@ export declare class Daemon extends EventEmitter {
746
731
  private authFailureUnresolved;
747
732
  /** One login-screen auth report per spawn — the screen persists across polls. */
748
733
  private loginScreenReported;
734
+ /** #2795: the auth pattern match the token-free check is still to judge; it arms nothing until confirmAuthFailure(). */
735
+ private unverifiedAuthMatch;
749
736
  /**
750
737
  * While the lifecycle is still starting this daemon, `pty_error` has no
751
738
  * listener and `InstanceLifecycle.daemons` has no entry — so an incident the
@@ -802,15 +789,12 @@ export declare class Daemon extends EventEmitter {
802
789
  private deliveryWritesStopping;
803
790
  /** #829: the latest pastes, by spawn generation (see ownedInputDraft). */
804
791
  private recentPastes;
805
- private pendingInstructionsUpdate;
806
- private pendingInstructionsNotice;
807
792
  /** #1633: the one-time "what's new for you" notice, pasted before the next real delivery; recorded once pasted. */
808
793
  private pendingWhatsNew;
809
- /** #2140: deliveries tried for the pending what's-new notice that never reached the pane (capped: never before every message). */
810
- private whatsNewUnwritten;
811
- private warmupNeeded;
812
- private lastBuiltInstructions;
813
794
  private pasteQueueDepth;
795
+ /** #2770: a person's messages a cancel dropped before they reached the CLI, told together (noteCancelledHuman). */
796
+ private cancelledHumans;
797
+ private cancelledHumansTimer;
814
798
  private firstDeliveryDelay;
815
799
  /** Orders /steer pastes against each other. Deliberately NOT pasteLock:
816
800
  * a steer must not queue behind the normal deliveries it exists to
@@ -947,6 +931,35 @@ export declare class Daemon extends EventEmitter {
947
931
  private lastErrorCount;
948
932
  private seededErrorCountBaselines;
949
933
  private lastDetectedErrorType;
934
+ /**
935
+ * #2822: Claude's per-model usage limit (`You've reached your <model> limit.`), known only from Claude's own record of
936
+ * the failed call in its transcript (`isApiErrorMessage`, a 429) — never from pane text, which an agent can print. It
937
+ * names no reset time. While it holds it is told once, and the reply guard stays quiet while the transcript's newest
938
+ * event is that error; any later assistant output (of any turn, from a person or not) ends it. The order is Claude's
939
+ * own: a 429 is recorded within a second, often before AgEnD has armed the turn, so no AgEnD-side clock is used.
940
+ */
941
+ private usageLimitHold;
942
+ /** Transcript events in Claude's order (prompts, output, every API error): the newest, and the latest limit error. */
943
+ private transcriptEventSeq;
944
+ private usageLimitErrorSeq;
945
+ static readonly MODEL_USAGE_LIMIT: RegExp;
946
+ /** #2822: the usage-limit hold, while it lasts — Needs you lists it. */
947
+ usageHold(): {
948
+ model: string;
949
+ since: number;
950
+ } | null;
951
+ /** #2822: Claude recorded a failed API call. */
952
+ private noteClaudeApiError;
953
+ /** #2822: Claude produced output (text or a tool call): the model answers again, so a hold ends. */
954
+ private noteClaudeOutput;
955
+ /** #2822: a prompt reached Claude (recorded in its transcript). */
956
+ private noteClaudePrompt;
957
+ /**
958
+ * #2822: the turn ended on the limit error — the transcript's newest event of any kind. A prompt after it (a new
959
+ * message the error is older than), output after it (the model answered) or another API error after it (a 500, a
960
+ * different 429) means the limit error is not this turn's end.
961
+ */
962
+ private personTurnEndedOnUsageLimit;
950
963
  private static errorPatternKey;
951
964
  /** Read the occurrence baseline so a lifecycle-owned restart can carry it forward. */
952
965
  /** #2648: kiro only — what a model error on the current launch should do (see kiro-retired-model.ts). */
@@ -960,21 +973,21 @@ export declare class Daemon extends EventEmitter {
960
973
  releaseStartupIncidents(): void;
961
974
  emit(event: string | symbol, ...args: unknown[]): boolean;
962
975
  /**
963
- * Undo the auth suspicion a pattern match armed, once the backend's token-free
964
- * probe has said the credentials are fine.
965
- *
966
- * emitErrorPattern arms these BEFORE the pty_error reaches the lifecycle, and
967
- * the lifecycle's "valid" verdict used to just drop the incident — leaving the
968
- * daemon permanently suspicious of an auth failure that never existed. That
969
- * state is not inert: authFailureUnresolved suppresses the stuck/hang
970
- * notification and holds MCP auto-restart (a later real MCP death is then read
971
- * as already-confirmed auth trouble rather than re-verified), and the recovery
972
- * gate suppresses further error detection until a ready pattern shows up.
973
- *
974
- * Only what an auth match armed is rolled back. If some other pattern has
975
- * since armed the recovery gate, that one is still live and stays.
976
+ * Undo an auth suspicion once the backend's token-free probe has said the credentials are fine. Since #2795 a pane
977
+ * pattern match arms nothing before that probe (its pending match is just dropped); what is left to undo is a
978
+ * login-screen report, which arms authFailureUnresolved itself. That state is not inert: it suppresses the
979
+ * stuck/hang notification and holds MCP auto-restart. If some other pattern has armed the recovery gate, that one
980
+ * is still live and stays.
976
981
  */
977
982
  clearSuspectedAuthFailure(): boolean;
983
+ private armErrorRecoveryGate;
984
+ /**
985
+ * #2795: the token-free check did not vouch for the credentials behind an auth pattern match. Only now does the
986
+ * match become an auth failure: the state the detector used to arm at match time. Remembered for as long as it is
987
+ * unresolved — an auth-broken CLI cannot finish the turn it is holding, so every other detector would otherwise
988
+ * keep reporting the same dead instance. A login-screen report arms its own state and has no match to confirm.
989
+ */
990
+ confirmAuthFailure(): boolean;
978
991
  private clearErrorRecoveryGate;
979
992
  constructor(name: string, config: InstanceConfig, instanceDir: string, topicMode?: boolean, backend?: CliBackend | undefined, controlClient?: TmuxControlClient | undefined, rootLogger?: Logger, runtimeIdentity?: FleetInstructionsParams["runtimeIdentity"], spawnGate?: SpawnGate | undefined, stormWindow?: StormWindow | undefined,
980
993
  /** Fleet-level "is this CLI's backend down?" memory — see backend-outage.ts. */
@@ -1466,8 +1479,6 @@ export declare class Daemon extends EventEmitter {
1466
1479
  private currentReplyRecovery;
1467
1480
  private queueMalformedReplyRecovery;
1468
1481
  private reportUnrecoveredReplyDrop;
1469
- /** Channel notice for a reply-drop. `rateLimit` shares the per-instance cooldown (#2544). */
1470
- private deliverReplyDropNotice;
1471
1482
  /** Relay the pane's final text to the channel, marked as a daemon proxy reply. */
1472
1483
  private sendProxyReply;
1473
1484
  /** Context-bound reply path shared by dead-MCP and malformed-call recovery. */
@@ -1485,6 +1496,12 @@ export declare class Daemon extends EventEmitter {
1485
1496
  private scheduleInstanceStateIdleCapture;
1486
1497
  private captureAndEvaluateInstanceState;
1487
1498
  private handleInstancePaneOutput;
1499
+ /**
1500
+ * The backend's structural idle proof for periodically repainting panes, when it applies to the current layout: always
1501
+ * for a backend that repaints in every layout (Codex, Muse), only while the latest capture showed such a layout for one
1502
+ * that names it (CliBackend.periodicRedrawFrom — Claude's background-agent list, #2770 (ii)).
1503
+ */
1504
+ private periodicIdleProof;
1488
1505
  private bindInstanceStateOutputListener;
1489
1506
  private startInstanceStateMonitor;
1490
1507
  private stopInstanceStateMonitor;
@@ -1572,6 +1589,13 @@ export declare class Daemon extends EventEmitter {
1572
1589
  /** The same formatter/sanitizer used by the actual write; snapshot only. */
1573
1590
  humanReceiptWire(content: string, meta: Record<string, string>, kind: string): string;
1574
1591
  private humanReceiptAttempt;
1592
+ /**
1593
+ * #2770: a person's message a cancel dropped before it reached the CLI is told, not left as a silent "uncertain":
1594
+ * the messages dropped together go out as one `human_messages_cancelled` (the fleet marks each ❌ and says so once).
1595
+ * Agents' messages are not a person's, and a durable row (delivery_id) is retried by the outbox: neither is ❌'d. A
1596
+ * message with no chat to mark has nowhere to say it.
1597
+ */
1598
+ private noteCancelledHuman;
1575
1599
  private finishHumanReceipt;
1576
1600
  /**
1577
1601
  * Whether ONE delivery reached a verdict, carried by that delivery.
@@ -1945,6 +1969,9 @@ export declare class Daemon extends EventEmitter {
1945
1969
  * Enter-dropping TUIs. Polls at a coarse cadence (each poll is a capture-pane)
1946
1970
  * only after the pane is already quiet, so the common fast-idle delivery still
1947
1971
  * costs a single capture.
1972
+ *
1973
+ * #2770: with `stop`, the wait also ends ("stopped") as soon as `stop` says so — asked every WAIT_STOP_POLL_MS while
1974
+ * the pane is busy, and before every re-poll — so a cancel or a hand-off that became possible never waits out the pane.
1948
1975
  */
1949
1976
  private waitForPaneReadyForDelivery;
1950
1977
  /**
@@ -2046,6 +2073,11 @@ export declare class Daemon extends EventEmitter {
2046
2073
  */
2047
2074
  private isPaneIdleForDelivery;
2048
2075
  private waitForPaneIdleForDelivery;
2076
+ /**
2077
+ * #2770: waitForPaneIdleForDelivery that also ends as soon as `stop` says so ("stopped"). The same idle readings
2078
+ * (tmux silence, or the state machine where its idle is trusted), polled here so nothing outlives a stopped wait.
2079
+ */
2080
+ private waitForPaneIdleOrStop;
2049
2081
  /**
2050
2082
  * Antigravity has always opted into pane-state delivery readiness because its
2051
2083
  * footer redraws while idle. Codex's structural idle proof is useful only
@@ -2419,22 +2451,17 @@ export declare class Daemon extends EventEmitter {
2419
2451
  */
2420
2452
  private switchMuseToDirect;
2421
2453
  /**
2422
- * Tell the agent its instructions moved, once the CLI is idle.
2423
- *
2424
- * A named method rather than an inline closure so the wiring itself is
2425
- * testable: warmupNoticeAction's own tests pass even if this call site stops
2426
- * consulting it, which is exactly the bug this path had — the decision was
2427
- * made inline and never asked whether the backend needed telling at all.
2428
- *
2429
- * Never throws: a missed reload notice must not fail a spawn.
2454
+ * #1633 (#1639 review): the pending notice as things stand NOW, just before the paste — it was decided at launch, and
2455
+ * the record, a switch or the instance's tools may have changed while the delivery waited. Planned again from the
2456
+ * record (#2800: the running release only, tools it has now); nothing left to tell → recorded, nothing pending.
2430
2457
  */
2431
- private runWarmupInstructionNotice;
2458
+ private currentWhatsNew;
2459
+ private recordWhatsNewSent;
2432
2460
  /**
2433
- * #1633 (#1639 review): the pending notice as the record stands NOW, just before the paste — it was decided at launch,
2434
- * and the record may have changed while the delivery waited. Unreadable → nothing is sent (and nothing pending);
2435
- * entries recorded meanwhile are dropped from it; none left → nothing.
2461
+ * #2800: the tools this instance's agend MCP server lists now — the same filters (tool set, dashboard switches, the
2462
+ * Canvas Worker switch) — so a notice names only changes to tools it has.
2436
2463
  */
2437
- private currentWhatsNew;
2464
+ private whatsNewTools;
2438
2465
  /**
2439
2466
  * #2163: who this instance is to the what's-new notices — a ClassicBot room's agent, General, or a fleet worker (with
2440
2467
  * `coordinator` too when its tool set is coordinator or full, the ones that carry get_/set_web_settings).