From 5c5745dee52bc5e2ab00b81f8160714b14da01d8 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Tue, 20 Jan 2026 16:37:34 +0000 Subject: [PATCH] fix: auto-enable plugins on startup --- src/gateway/server.impl.ts | 15 ++++++++++++++ src/gateway/server.misc.test.ts | 36 +++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+) diff --git a/src/gateway/server.impl.ts b/src/gateway/server.impl.ts index 11da41275..898ed1ca7 100644 --- a/src/gateway/server.impl.ts +++ b/src/gateway/server.impl.ts @@ -13,6 +13,7 @@ import { readConfigFileSnapshot, writeConfigFile, } from "../config/config.js"; +import { applyPluginAutoEnable } from "../config/plugin-auto-enable.js"; import { clearAgentRunContext, onAgentEvent } from "../infra/agent-events.js"; import { onHeartbeatEvent } from "../infra/heartbeat-events.js"; import { startHeartbeatRunner } from "../infra/heartbeat-runner.js"; @@ -182,6 +183,20 @@ export async function startGatewayServer( ); } + const autoEnable = applyPluginAutoEnable({ config: configSnapshot.config, env: process.env }); + if (autoEnable.changes.length > 0) { + try { + await writeConfigFile(autoEnable.config); + log.info( + `gateway: auto-enabled plugins:\n${autoEnable.changes + .map((entry) => `- ${entry}`) + .join("\n")}`, + ); + } catch (err) { + log.warn(`gateway: failed to persist plugin auto-enable changes: ${String(err)}`); + } + } + const cfgAtStart = loadConfig(); setGatewaySigusr1RestartPolicy({ allowExternal: cfgAtStart.commands?.restart === true }); initSubagentRegistry(); diff --git a/src/gateway/server.misc.test.ts b/src/gateway/server.misc.test.ts index 0e705f8b5..c0be52135 100644 --- a/src/gateway/server.misc.test.ts +++ b/src/gateway/server.misc.test.ts @@ -1,4 +1,6 @@ +import fs from "node:fs/promises"; import { createServer } from "node:net"; +import path from "node:path"; import { describe, expect, test } from "vitest"; import { resolveCanvasHostUrl } from "../infra/canvas-host-url.js"; import { getChannelPlugin } from "../channels/plugins/index.js"; @@ -129,6 +131,40 @@ describe("gateway server misc", () => { } }); + test("auto-enables configured channel plugins on startup", async () => { + const configPath = process.env.CLAWDBOT_CONFIG_PATH; + if (!configPath) throw new Error("Missing CLAWDBOT_CONFIG_PATH"); + await fs.mkdir(path.dirname(configPath), { recursive: true }); + await fs.writeFile( + configPath, + JSON.stringify( + { + channels: { + discord: { + token: "token-123", + }, + }, + }, + null, + 2, + ), + "utf-8", + ); + + const port = await getFreePort(); + const server = await startGatewayServer(port); + await server.close(); + + const updated = JSON.parse(await fs.readFile(configPath, "utf-8")) as Record; + const plugins = updated.plugins as Record | undefined; + const entries = plugins?.entries as Record | undefined; + const discord = entries?.discord as Record | undefined; + expect(discord?.enabled).toBe(true); + expect((updated.channels as Record | undefined)?.discord).toMatchObject({ + token: "token-123", + }); + }); + test("refuses to start when port already bound", async () => { const { server: blocker, port } = await occupyPort(); await expect(startGatewayServer(port)).rejects.toBeInstanceOf(GatewayLockError);