@songsid/agend 2.0.11-beta.26 → 2.0.11-beta.28

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.
@@ -8,6 +8,8 @@ import { sdNotify } from "./sd-notify.js";
8
8
  import yaml from "js-yaml";
9
9
  const __filename = fileURLToPath(import.meta.url);
10
10
  const __dirname = dirname(__filename);
11
+ /** Fallback access policy for a channel with no `access:` block — open (no gate). */
12
+ const DEFAULT_OPEN_ACCESS = { mode: "open", allowed_users: [], max_pending_codes: 0, code_expiry_minutes: 0 };
11
13
  import { isProbeableRouteTarget } from "./fleet-context.js";
12
14
  import { loadFleetConfig, DEFAULT_COST_GUARD, DEFAULT_DAILY_SUMMARY, DEFAULT_INSTANCE_CONFIG } from "./config.js";
13
15
  import { EventLog } from "./event-log.js";
@@ -678,6 +680,23 @@ export class FleetManager {
678
680
  }
679
681
  }
680
682
  }
683
+ // Guard against a stale/invalid general topic_id. An old auto-general
684
+ // could have written the TG-convention "1" for a Discord general; the DC
685
+ // adapter then throws fetching channel "1" → unhandled → fleet crash loop.
686
+ // Unbind (+ warn) so it's simply skipped, never routed to a bogus channel.
687
+ let fixedGeneral = false;
688
+ for (const [name, cfg] of Object.entries(this.fleetConfig.instances)) {
689
+ if (!cfg.general_topic || cfg.topic_id == null)
690
+ continue;
691
+ const adapterId = this.instanceWorldBinding.get(name) ?? cfg.channel_id;
692
+ if (this.getChannelConfig(adapterId)?.type === "discord" && !/^\d{17,}$/.test(String(cfg.topic_id))) {
693
+ this.logger.warn({ name, topic_id: cfg.topic_id }, "Discord general topic_id is not a valid channel — unbinding to avoid a crash loop");
694
+ delete cfg.topic_id;
695
+ fixedGeneral = true;
696
+ }
697
+ }
698
+ if (fixedGeneral)
699
+ this.saveFleetConfig();
681
700
  // Auto-create topics AFTER adapter is ready (needs adapter.createTopic)
682
701
  await this.topicCommands.autoCreateTopics();
683
702
  const routeSummary = this.routing.rebuild(this.fleetConfig);
@@ -820,7 +839,7 @@ export class FleetManager {
820
839
  }
821
840
  const accessDir = join(this.dataDir, "access");
822
841
  mkdirSync(accessDir, { recursive: true });
823
- const accessManager = new AccessManager(channelConfig.access, join(accessDir, "access.json"));
842
+ const accessManager = new AccessManager(channelConfig.access ?? DEFAULT_OPEN_ACCESS, join(accessDir, "access.json"));
824
843
  this.accessManager = accessManager;
825
844
  const inboxDir = join(this.dataDir, "inbox");
826
845
  mkdirSync(inboxDir, { recursive: true });
@@ -1103,7 +1122,7 @@ export class FleetManager {
1103
1122
  }
1104
1123
  const accessDir = join(this.dataDir, "access");
1105
1124
  mkdirSync(accessDir, { recursive: true });
1106
- const accessManager = new AccessManager(channelConfig.access, join(accessDir, `access-${adapterId}.json`));
1125
+ const accessManager = new AccessManager(channelConfig.access ?? DEFAULT_OPEN_ACCESS, join(accessDir, `access-${adapterId}.json`));
1107
1126
  const inboxDir = join(this.dataDir, "inbox");
1108
1127
  mkdirSync(inboxDir, { recursive: true });
1109
1128
  const adapter = await createAdapter(channelConfig, {