diff --git a/src/cron/store.ts b/src/cron/store.ts index 995c7dfbf3d..6f0e3e40954 100644 --- a/src/cron/store.ts +++ b/src/cron/store.ts @@ -1,3 +1,4 @@ +import { randomBytes } from "node:crypto"; import fs from "node:fs"; import path from "node:path"; import JSON5 from "json5"; @@ -7,6 +8,7 @@ import type { CronStoreFile } from "./types.js"; export const DEFAULT_CRON_DIR = path.join(CONFIG_DIR, "cron"); export const DEFAULT_CRON_STORE_PATH = path.join(DEFAULT_CRON_DIR, "jobs.json"); +const serializedStoreCache = new Map(); export function resolveCronStorePath(storePath?: string) { if (storePath?.trim()) { @@ -35,12 +37,15 @@ export async function loadCronStore(storePath: string): Promise { ? (parsed as Record) : {}; const jobs = Array.isArray(parsedRecord.jobs) ? (parsedRecord.jobs as never[]) : []; - return { - version: 1, + const store = { + version: 1 as const, jobs: jobs.filter(Boolean) as never as CronStoreFile["jobs"], }; + serializedStoreCache.set(storePath, JSON.stringify(store, null, 2)); + return store; } catch (err) { if ((err as { code?: unknown })?.code === "ENOENT") { + serializedStoreCache.delete(storePath); return { version: 1, jobs: [] }; } throw err; @@ -49,17 +54,24 @@ export async function loadCronStore(storePath: string): Promise { export async function saveCronStore(storePath: string, store: CronStoreFile) { await fs.promises.mkdir(path.dirname(storePath), { recursive: true }); - const { randomBytes } = await import("node:crypto"); const json = JSON.stringify(store, null, 2); - let previous: string | null = null; - try { - previous = await fs.promises.readFile(storePath, "utf-8"); - } catch (err) { - if ((err as { code?: unknown }).code !== "ENOENT") { - throw err; + const cached = serializedStoreCache.get(storePath); + if (cached === json) { + return; + } + + let previous: string | null = cached ?? null; + if (previous === null) { + try { + previous = await fs.promises.readFile(storePath, "utf-8"); + } catch (err) { + if ((err as { code?: unknown }).code !== "ENOENT") { + throw err; + } } } if (previous === json) { + serializedStoreCache.set(storePath, json); return; } const tmp = `${storePath}.${process.pid}.${randomBytes(8).toString("hex")}.tmp`; @@ -72,6 +84,7 @@ export async function saveCronStore(storePath: string, store: CronStoreFile) { } } await renameWithRetry(tmp, storePath); + serializedStoreCache.set(storePath, json); } const RENAME_MAX_RETRIES = 3; diff --git a/src/logging/subsystem.ts b/src/logging/subsystem.ts index ab73bc0b35c..cfea654b479 100644 --- a/src/logging/subsystem.ts +++ b/src/logging/subsystem.ts @@ -279,6 +279,13 @@ export function createSubsystemLogger(subsystem: string): SubsystemLogger { }; const emit = (level: LogLevel, message: string, meta?: Record) => { const consoleSettings = getConsoleSettings(); + const consoleEnabled = + shouldLogToConsole(level, { level: consoleSettings.level }) && + shouldLogSubsystemToConsole(subsystem); + const fileEnabled = isFileLogLevelEnabled(level); + if (!consoleEnabled && !fileEnabled) { + return; + } let consoleMessageOverride: string | undefined; let fileMeta = meta; if (meta && Object.keys(meta).length > 0) { @@ -290,11 +297,10 @@ export function createSubsystemLogger(subsystem: string): SubsystemLogger { } fileMeta = Object.keys(rest).length > 0 ? rest : undefined; } - logToFile(getFileLogger(), level, message, fileMeta); - if (!shouldLogToConsole(level, { level: consoleSettings.level })) { - return; + if (fileEnabled) { + logToFile(getFileLogger(), level, message, fileMeta); } - if (!shouldLogSubsystemToConsole(subsystem)) { + if (!consoleEnabled) { return; } const consoleMessage = consoleMessageOverride ?? message; @@ -341,8 +347,10 @@ export function createSubsystemLogger(subsystem: string): SubsystemLogger { error: (message, meta) => emit("error", message, meta), fatal: (message, meta) => emit("fatal", message, meta), raw: (message) => { - logToFile(getFileLogger(), "info", message, { raw: true }); - if (shouldLogSubsystemToConsole(subsystem)) { + if (isFileEnabled("info")) { + logToFile(getFileLogger(), "info", message, { raw: true }); + } + if (isConsoleEnabled("info")) { if ( !isVerbose() && subsystem === "agent/embedded" && diff --git a/src/memory/qmd-manager.ts b/src/memory/qmd-manager.ts index 01acf9612cd..a2d3accef83 100644 --- a/src/memory/qmd-manager.ts +++ b/src/memory/qmd-manager.ts @@ -187,6 +187,7 @@ export class QmdMemoryManager implements MemorySearchManager { private readonly xdgCacheHome: string; private readonly indexPath: string; private readonly env: NodeJS.ProcessEnv; + private readonly managedCollectionNames: string[]; private readonly collectionRoots = new Map(); private readonly sources = new Set(); private readonly docPathCache = new Map< @@ -261,6 +262,7 @@ export class QmdMemoryManager implements MemorySearchManager { }, ]; } + this.managedCollectionNames = this.computeManagedCollectionNames(); } private async initialize(mode: QmdManagerMode): Promise { @@ -1913,6 +1915,10 @@ export class QmdMemoryManager implements MemorySearchManager { } private listManagedCollectionNames(): string[] { + return this.managedCollectionNames; + } + + private computeManagedCollectionNames(): string[] { const seen = new Set(); const names: string[] = []; for (const collection of this.qmd.collections) {