@songsid/agend 2.1.11-beta.4 → 2.1.11-beta.5

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.
@@ -955,6 +955,11 @@ export declare class FleetManager implements FleetContext, LifecycleContext, Arc
955
955
  };
956
956
  /** Start the primary adapter (backward-compatible, sets this.adapter) */
957
957
  private startSingleAdapter;
958
+ /**
959
+ * Register a Telegram connection's command menus; any other kind of channel has none to register. Started, not
960
+ * awaited: a slow api.telegram.org must never hold up the adapter's login (each call has its own timeout). Never fatal.
961
+ */
962
+ private registerTelegramCommandsFor;
958
963
  /** Start an additional (non-primary) adapter */
959
964
  private startAdditionalAdapter;
960
965
  /** Connect IPC to a single instance with all handlers */
@@ -2131,6 +2136,11 @@ export declare class FleetManager implements FleetContext, LifecycleContext, Arc
2131
2136
  private effortSuffix;
2132
2137
  /** Read recent chat log for agent context */
2133
2138
  private getRecentChatLog;
2139
+ /**
2140
+ * The ClassicBot /start replies say how to talk to the agent, and that differs by platform (#1196): on Telegram
2141
+ * you @mention the bot; on Discord, @mention or `/chat`. The chat's platform is the adapter it came through.
2142
+ */
2143
+ private classicStartKey;
2134
2144
  /** Return a user-facing blocker without mutating ClassicBot state. */
2135
2145
  private validateClassicStart;
2136
2146
  private isBackendInstalled;
@@ -2794,10 +2794,8 @@ export class FleetManager {
2794
2794
  // it before lifecycle.start() can turn a crash-loop daemon's dead pane into
2795
2795
  // a falsely running instance when lifecycle.start() returns early.
2796
2796
  this.instanceProcessStatus.delete(name);
2797
- try {
2798
- unlinkSync(join(this.getInstanceDir(name), "crash-state.json"));
2799
- }
2800
- catch { /* consumed or absent */ }
2797
+ // Recovery intent belongs to Daemon.start. lifecycle.start can return
2798
+ // before reaching it, so an await here is not proof the marker was read.
2801
2799
  // Auto-connect IPC — daemon.start() ensures socket is ready before resolving
2802
2800
  await this.connectIpcToInstance(name);
2803
2801
  this.requestDiscordUsagePresenceRefresh();
@@ -4517,7 +4515,8 @@ export class FleetManager {
4517
4515
  return;
4518
4516
  await this.dispatchSlash(data, adapterId, adapter);
4519
4517
  }, this.logger, "adapter.slash_command"));
4520
- await this.topicCommands.registerBotCommands().catch(e => this.logger.warn({ err: e }, "registerBotCommands failed (non-fatal)"));
4518
+ // This adapter's own Telegram menus — each Telegram adapter registers its own when it starts (#1191).
4519
+ this.registerTelegramCommandsFor(channelConfig);
4521
4520
  // Background-probe each backend's CLI env (version/models) → cli-env cache.
4522
4521
  // Non-blocking: /model & status views read the cache; never delays startup.
4523
4522
  this.probeCliEnvs();
@@ -4572,6 +4571,15 @@ export class FleetManager {
4572
4571
  this.pruneStaleExternalSessions().catch(err => this.logger.debug({ err }, "Session prune failed"));
4573
4572
  }, 5 * 60 * 1000);
4574
4573
  }
4574
+ /**
4575
+ * Register a Telegram connection's command menus; any other kind of channel has none to register. Started, not
4576
+ * awaited: a slow api.telegram.org must never hold up the adapter's login (each call has its own timeout). Never fatal.
4577
+ */
4578
+ registerTelegramCommandsFor(channelConfig) {
4579
+ if (channelConfig.type !== "telegram")
4580
+ return;
4581
+ void this.topicCommands.registerBotCommands(channelConfig).catch(e => this.logger.warn({ err: e, adapterId: channelConfig.id ?? channelConfig.type }, "registerBotCommands failed (non-fatal)"));
4582
+ }
4575
4583
  /** Start an additional (non-primary) adapter */
4576
4584
  async startAdditionalAdapter(channelConfig, registerCommands = true, onStarted) {
4577
4585
  const adapterId = channelConfig.id ?? channelConfig.type;
@@ -4647,6 +4655,9 @@ export class FleetManager {
4647
4655
  this.logger.error({ err, adapterId }, "Additional adapter fatal error");
4648
4656
  this.restartAdapter(adapter, adapterId).catch(() => { });
4649
4657
  });
4658
+ // A secondary Telegram connection (a ClassicBot next to a Discord fleet, say) has menus of its own to register —
4659
+ // at fleet start, on retry, and when Settings rebinds it or rotates its token: all of them start it here (#1191).
4660
+ this.registerTelegramCommandsFor(channelConfig);
4650
4661
  // Register lifecycle listeners before login; a fast ready/error must not be lost.
4651
4662
  await adapter.start();
4652
4663
  if (channelConfig.group_id) {
@@ -11923,6 +11934,14 @@ Plus the operational skills (fleet-health, instance-lifecycle, scheduling, sessi
11923
11934
  return undefined;
11924
11935
  }
11925
11936
  }
11937
+ /**
11938
+ * The ClassicBot /start replies say how to talk to the agent, and that differs by platform (#1196): on Telegram
11939
+ * you @mention the bot; on Discord, @mention or `/chat`. The chat's platform is the adapter it came through.
11940
+ */
11941
+ classicStartKey(key, adapterId) {
11942
+ const adapter = (adapterId ? this.worlds.get(adapterId)?.adapter : undefined) ?? this.adapter;
11943
+ return adapter?.type === "telegram" ? `${key}.telegram` : key;
11944
+ }
11926
11945
  /** Return a user-facing blocker without mutating ClassicBot state. */
11927
11946
  validateClassicStart(channelId, userId, guildId, adapterId) {
11928
11947
  if (!this.classicChannels)
@@ -11944,7 +11963,7 @@ Plus the operational skills (fleet-health, instance-lifecycle, scheduling, sessi
11944
11963
  return t("classic.not_authorized_guild");
11945
11964
  }
11946
11965
  if (this.classicChannels.isClassicChannel(channelId, adapterId))
11947
- return t("classic.already_active");
11966
+ return t(this.classicStartKey("classic.already_active", adapterId));
11948
11967
  if (this.routing.resolve(channelId))
11949
11968
  return t("classic.topic_bound");
11950
11969
  return undefined;
@@ -12131,7 +12150,7 @@ Plus the operational skills (fleet-health, instance-lifecycle, scheduling, sessi
12131
12150
  classicChannels.toggleCollab(channelId, adapterId);
12132
12151
  }
12133
12152
  this.logger.info({ channelId, adapterId, instanceName, userId }, "Classic channel started");
12134
- return t("classic.started");
12153
+ return t(this.classicStartKey("classic.started", adapterId));
12135
12154
  }
12136
12155
  /** Handle /stop slash command — unregister classic channel */
12137
12156
  async handleClassicStop(channelId, adapterId) {