fix: unblock bundled plugin load

This commit is contained in:
Peter Steinberger
2026-01-18 19:33:58 +00:00
parent bf3021d266
commit 601a052216
17 changed files with 136 additions and 16 deletions

View File

@@ -8,6 +8,7 @@ const execSyncMock = vi.fn();
describe("cli credentials", () => {
beforeEach(() => {
vi.resetModules();
vi.useFakeTimers();
});

View File

@@ -39,6 +39,7 @@ vi.mock("../config/sessions.js", () => ({
resolveAgentIdFromSessionKey: () => "main",
resolveStorePath: () => "/tmp/sessions.json",
resolveMainSessionKey: () => "agent:main:main",
readSessionUpdatedAt: vi.fn(() => undefined),
recordSessionMetaFromInbound: vi.fn().mockResolvedValue(undefined),
}));

View File

@@ -39,6 +39,19 @@ vi.mock("../config/config.js", () => ({
}));
describe("pairing cli", () => {
it("evaluates pairing channels when registering the CLI (not at import)", async () => {
listPairingChannels.mockClear();
const { registerPairingCli } = await import("./pairing-cli.js");
expect(listPairingChannels).not.toHaveBeenCalled();
const program = new Command();
program.name("test");
registerPairingCli(program);
expect(listPairingChannels).toHaveBeenCalledTimes(1);
});
it("labels Telegram ids as telegramUserId", async () => {
const { registerPairingCli } = await import("./pairing-cli.js");
listChannelPairingRequests.mockResolvedValueOnce([

View File

@@ -24,6 +24,7 @@ vi.mock("../config/config.js", async (importOriginal) => {
vi.mock("../config/sessions.js", () => ({
resolveStorePath: () => "/tmp/sessions.json",
loadSessionStore: () => testStore,
readSessionUpdatedAt: vi.fn(() => undefined),
recordSessionMetaFromInbound: vi.fn().mockResolvedValue(undefined),
updateLastRoute: vi.fn().mockResolvedValue(undefined),
}));

View File

@@ -100,6 +100,7 @@ vi.mock("../config/sessions.js", () => ({
loadSessionStore: mocks.loadSessionStore,
resolveMainSessionKey: mocks.resolveMainSessionKey,
resolveStorePath: mocks.resolveStorePath,
readSessionUpdatedAt: vi.fn(() => undefined),
recordSessionMetaFromInbound: vi.fn().mockResolvedValue(undefined),
}));
vi.mock("../channels/plugins/index.js", () => ({

View File

@@ -38,6 +38,7 @@ vi.mock("../pairing/pairing-store.js", () => ({
vi.mock("../config/sessions.js", () => ({
resolveStorePath: vi.fn(() => "/tmp/clawdbot-sessions.json"),
updateLastRoute: (...args: unknown[]) => updateLastRouteMock(...args),
readSessionUpdatedAt: vi.fn(() => undefined),
recordSessionMetaFromInbound: vi.fn().mockResolvedValue(undefined),
}));

View File

@@ -38,6 +38,7 @@ vi.mock("../pairing/pairing-store.js", () => ({
vi.mock("../config/sessions.js", () => ({
resolveStorePath: vi.fn(() => "/tmp/clawdbot-sessions.json"),
updateLastRoute: (...args: unknown[]) => updateLastRouteMock(...args),
readSessionUpdatedAt: vi.fn(() => undefined),
recordSessionMetaFromInbound: vi.fn().mockResolvedValue(undefined),
}));

View File

@@ -1,4 +1,4 @@
export {
import {
enableConsoleCapture,
getConsoleSettings,
getResolvedConsoleSettings,
@@ -7,10 +7,10 @@ export {
setConsoleTimestampPrefix,
shouldLogSubsystemToConsole,
} from "./logging/console.js";
export type { ConsoleLoggerSettings, ConsoleStyle } from "./logging/console.js";
export type { LogLevel } from "./logging/levels.js";
export { ALLOWED_LOG_LEVELS, levelToMinLevel, normalizeLogLevel } from "./logging/levels.js";
export {
import type { ConsoleLoggerSettings, ConsoleStyle } from "./logging/console.js";
import { ALLOWED_LOG_LEVELS, levelToMinLevel, normalizeLogLevel } from "./logging/levels.js";
import type { LogLevel } from "./logging/levels.js";
import {
DEFAULT_LOG_DIR,
DEFAULT_LOG_FILE,
getChildLogger,
@@ -21,11 +21,47 @@ export {
setLoggerOverride,
toPinoLikeLogger,
} from "./logging/logger.js";
export type { LoggerResolvedSettings, LoggerSettings, PinoLikeLogger } from "./logging/logger.js";
export {
import type { LoggerResolvedSettings, LoggerSettings, PinoLikeLogger } from "./logging/logger.js";
import {
createSubsystemLogger,
createSubsystemRuntime,
runtimeForLogger,
stripRedundantSubsystemPrefixForConsole,
} from "./logging/subsystem.js";
export type { SubsystemLogger } from "./logging/subsystem.js";
import type { SubsystemLogger } from "./logging/subsystem.js";
export {
enableConsoleCapture,
getConsoleSettings,
getResolvedConsoleSettings,
routeLogsToStderr,
setConsoleSubsystemFilter,
setConsoleTimestampPrefix,
shouldLogSubsystemToConsole,
ALLOWED_LOG_LEVELS,
levelToMinLevel,
normalizeLogLevel,
DEFAULT_LOG_DIR,
DEFAULT_LOG_FILE,
getChildLogger,
getLogger,
getResolvedLoggerSettings,
isFileLogLevelEnabled,
resetLogger,
setLoggerOverride,
toPinoLikeLogger,
createSubsystemLogger,
createSubsystemRuntime,
runtimeForLogger,
stripRedundantSubsystemPrefixForConsole,
};
export type {
ConsoleLoggerSettings,
ConsoleStyle,
LogLevel,
LoggerResolvedSettings,
LoggerSettings,
PinoLikeLogger,
SubsystemLogger,
};

View File

@@ -1,6 +1,7 @@
import { createRequire } from "node:module";
import util from "node:util";
import { type ClawdbotConfig, loadConfig } from "../config/config.js";
import type { ClawdbotConfig } from "../config/config.js";
import { isVerbose } from "../globals.js";
import { stripAnsi } from "../terminal/ansi.js";
import { type LogLevel, normalizeLogLevel } from "./levels.js";
@@ -14,6 +15,8 @@ type ConsoleSettings = {
};
export type ConsoleLoggerSettings = ConsoleSettings;
const requireConfig = createRequire(import.meta.url);
function normalizeConsoleLevel(level?: string): LogLevel {
if (isVerbose()) return "debug";
return normalizeLogLevel(level, "info");
@@ -28,8 +31,19 @@ function normalizeConsoleStyle(style?: string): ConsoleStyle {
}
function resolveConsoleSettings(): ConsoleSettings {
const cfg: ClawdbotConfig["logging"] | undefined =
(loggingState.overrideSettings as LoggerSettings | null) ?? loadConfig().logging;
let cfg: ClawdbotConfig["logging"] | undefined;
if (loggingState.overrideSettings) {
cfg = loggingState.overrideSettings as LoggerSettings;
} else {
try {
const loaded = requireConfig("../config/config.js") as {
loadConfig?: () => ClawdbotConfig;
};
cfg = loaded.loadConfig?.().logging;
} catch {
cfg = undefined;
}
}
const level = normalizeConsoleLevel(cfg?.consoleLevel);
const style = normalizeConsoleStyle(cfg?.consoleStyle);
return { level, style };

View File

@@ -1,9 +1,10 @@
import { createRequire } from "node:module";
import fs from "node:fs";
import path from "node:path";
import { Logger as TsLogger } from "tslog";
import { type ClawdbotConfig, loadConfig } from "../config/config.js";
import type { ClawdbotConfig } from "../config/config.js";
import type { ConsoleStyle } from "./console.js";
import { type LogLevel, levelToMinLevel, normalizeLogLevel } from "./levels.js";
import { loggingState } from "./state.js";
@@ -17,6 +18,8 @@ const LOG_PREFIX = "clawdbot";
const LOG_SUFFIX = ".log";
const MAX_LOG_AGE_MS = 24 * 60 * 60 * 1000; // 24h
const requireConfig = createRequire(import.meta.url);
export type LoggerSettings = {
level?: LogLevel;
file?: string;
@@ -33,8 +36,19 @@ type ResolvedSettings = {
export type LoggerResolvedSettings = ResolvedSettings;
function resolveSettings(): ResolvedSettings {
const cfg: ClawdbotConfig["logging"] | undefined =
(loggingState.overrideSettings as LoggerSettings | null) ?? loadConfig().logging;
let cfg: ClawdbotConfig["logging"] | undefined;
if (loggingState.overrideSettings) {
cfg = loggingState.overrideSettings as LoggerSettings;
} else {
try {
const loaded = requireConfig("../config/config.js") as {
loadConfig?: () => ClawdbotConfig;
};
cfg = loaded.loadConfig?.().logging;
} catch {
cfg = undefined;
}
}
const level = normalizeLogLevel(cfg?.level, "info");
const file = cfg?.file ?? defaultRollingPathForToday();
return { level, file };

View File

@@ -1,4 +1,8 @@
import { loadConfig } from "../config/config.js";
import { createRequire } from "node:module";
import type { ClawdbotConfig } from "../config/config.js";
const requireConfig = createRequire(import.meta.url);
export type RedactSensitiveMode = "off" | "tools";
@@ -93,7 +97,15 @@ function redactText(text: string, patterns: RegExp[]): string {
}
function resolveConfigRedaction(): RedactOptions {
const cfg = loadConfig().logging;
let cfg: ClawdbotConfig["logging"] | undefined;
try {
const loaded = requireConfig("../config/config.js") as {
loadConfig?: () => ClawdbotConfig;
};
cfg = loaded.loadConfig?.().logging;
} catch {
cfg = undefined;
}
return {
mode: normalizeMode(cfg?.redactSensitive),
patterns: cfg?.redactPatterns,

View File

@@ -75,6 +75,26 @@ describe("loadClawdbotPlugins", () => {
expect(enabled?.status).toBe("loaded");
});
it("loads bundled telegram plugin when enabled", () => {
process.env.CLAWDBOT_BUNDLED_PLUGINS_DIR = path.join(process.cwd(), "extensions");
const registry = loadClawdbotPlugins({
cache: false,
config: {
plugins: {
allow: ["telegram"],
entries: {
telegram: { enabled: true },
},
},
},
});
const telegram = registry.plugins.find((entry) => entry.id === "telegram");
expect(telegram?.status).toBe("loaded");
expect(registry.channels.some((entry) => entry.plugin.id === "telegram")).toBe(true);
});
it("enables bundled memory plugin when selected by slot", () => {
const bundledDir = makeTempDir();
const bundledPath = path.join(bundledDir, "memory-core.ts");

View File

@@ -35,6 +35,7 @@ vi.mock("../pairing/pairing-store.js", () => ({
vi.mock("../config/sessions.js", () => ({
resolveStorePath: vi.fn(() => "/tmp/clawdbot-sessions.json"),
updateLastRoute: (...args: unknown[]) => updateLastRouteMock(...args),
readSessionUpdatedAt: vi.fn(() => undefined),
recordSessionMetaFromInbound: vi.fn().mockResolvedValue(undefined),
}));

View File

@@ -39,6 +39,7 @@ vi.mock("../pairing/pairing-store.js", () => ({
vi.mock("../config/sessions.js", () => ({
resolveStorePath: vi.fn(() => "/tmp/clawdbot-sessions.json"),
updateLastRoute: (...args: unknown[]) => updateLastRouteMock(...args),
readSessionUpdatedAt: vi.fn(() => undefined),
recordSessionMetaFromInbound: vi.fn().mockResolvedValue(undefined),
}));

View File

@@ -54,6 +54,7 @@ vi.mock("../config/sessions.js", () => ({
resolveStorePath: vi.fn(() => "/tmp/clawdbot-sessions.json"),
updateLastRoute: (...args: unknown[]) => updateLastRouteMock(...args),
resolveSessionKey: vi.fn(),
readSessionUpdatedAt: vi.fn(() => undefined),
recordSessionMetaFromInbound: vi.fn().mockResolvedValue(undefined),
}));

View File

@@ -56,6 +56,7 @@ vi.mock("../config/sessions.js", () => ({
resolveStorePath: vi.fn(() => "/tmp/clawdbot-sessions.json"),
updateLastRoute: (...args: unknown[]) => updateLastRouteMock(...args),
resolveSessionKey: vi.fn(),
readSessionUpdatedAt: vi.fn(() => undefined),
recordSessionMetaFromInbound: vi.fn().mockResolvedValue(undefined),
}));

View File

@@ -54,6 +54,7 @@ vi.mock("../config/sessions.js", () => ({
resolveStorePath: vi.fn(() => "/tmp/clawdbot-sessions.json"),
updateLastRoute: (...args: unknown[]) => updateLastRouteMock(...args),
resolveSessionKey: vi.fn(),
readSessionUpdatedAt: vi.fn(() => undefined),
recordSessionMetaFromInbound: vi.fn().mockResolvedValue(undefined),
}));