Bug
monitorMSTeamsProvider() in extensions/msteams/src/monitor.ts returns immediately after starting the Express server. The channel manager in src/gateway/server-channels.ts treats promise resolution as "provider stopped" and triggers auto-restart with exponential backoff, resulting in an infinite restart loop:
[msteams] [default] starting provider (port 3978)
[msteams] [default] auto-restart attempt 1/10 in 5s
[msteams] [default] starting provider (port 3978)
[msteams] [default] auto-restart attempt 2/10 in 10s
...
This cycles through all 10 attempts, then the health-monitor restarts the whole sequence indefinitely.
Root cause
The Slack provider (src/slack/monitor/provider.ts:355-359) correctly blocks until the abort signal fires:
await new Promise<void>((resolve) => {
opts.abortSignal?.addEventListener("abort", () => resolve(), { once: true });
});
The msteams provider is missing this — it just returns { app, shutdown } after expressApp.listen().
Fix
Add the same blocking pattern before the return in extensions/msteams/src/monitor.ts:
// Block until abort signal fires — the channel manager treats promise
// resolution as "provider stopped" and triggers auto-restart.
await new Promise<void>((resolve) => {
if (opts.abortSignal?.aborted) {
resolve();
return;
}
opts.abortSignal?.addEventListener("abort", () => resolve(), { once: true });
});
Also add { once: true } to the existing abort listener to prevent leaks:
if (opts.abortSignal) {
opts.abortSignal.addEventListener("abort", () => {
void shutdown();
}, { once: true });
}
Bug
monitorMSTeamsProvider()inextensions/msteams/src/monitor.tsreturns immediately after starting the Express server. The channel manager insrc/gateway/server-channels.tstreats promise resolution as "provider stopped" and triggers auto-restart with exponential backoff, resulting in an infinite restart loop:This cycles through all 10 attempts, then the health-monitor restarts the whole sequence indefinitely.
Root cause
The Slack provider (
src/slack/monitor/provider.ts:355-359) correctly blocks until the abort signal fires:The msteams provider is missing this — it just returns
{ app, shutdown }afterexpressApp.listen().Fix
Add the same blocking pattern before the return in
extensions/msteams/src/monitor.ts:Also add
{ once: true }to the existing abort listener to prevent leaks: