From 6464cf4756b1b7694374babb76adcbd2405bae27 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Mon, 20 Apr 2026 23:30:49 +0100 Subject: [PATCH] refactor: share plugin package version lookup --- extensions/feishu/src/client.ts | 27 +++++--------------------- extensions/qqbot/src/api.ts | 22 ++------------------- extensions/qqbot/src/slash-commands.ts | 22 ++------------------- src/plugin-sdk/extension-shared.ts | 26 +++++++++++++++++++++++++ 4 files changed, 35 insertions(+), 62 deletions(-) diff --git a/extensions/feishu/src/client.ts b/extensions/feishu/src/client.ts index 4c1ab41da22..dc8da9e4c21 100644 --- a/extensions/feishu/src/client.ts +++ b/extensions/feishu/src/client.ts @@ -1,31 +1,14 @@ import type { Agent } from "node:https"; import { createRequire } from "node:module"; import * as Lark from "@larksuiteoapi/node-sdk"; -import { resolveAmbientNodeProxyAgent } from "openclaw/plugin-sdk/extension-shared"; +import { + readPluginPackageVersion, + resolveAmbientNodeProxyAgent, +} from "openclaw/plugin-sdk/extension-shared"; import type { FeishuConfig, FeishuDomain, ResolvedFeishuAccount } from "./types.js"; const require = createRequire(import.meta.url); -const PACKAGE_JSON_CANDIDATES = [ - "../package.json", - "./package.json", - "../../package.json", -] as const; - -function readPluginVersion(): string { - for (const candidate of PACKAGE_JSON_CANDIDATES) { - try { - const version = (require(candidate) as { version?: unknown }).version; - if (typeof version === "string" && version.trim().length > 0) { - return version; - } - } catch { - // Ignore missing candidate paths across source and bundled layouts. - } - } - return "unknown"; -} - -const pluginVersion = readPluginVersion(); +const pluginVersion = readPluginPackageVersion({ require }); export { pluginVersion }; diff --git a/extensions/qqbot/src/api.ts b/extensions/qqbot/src/api.ts index 43e9fd4be1e..3b7b7160db9 100644 --- a/extensions/qqbot/src/api.ts +++ b/extensions/qqbot/src/api.ts @@ -1,6 +1,7 @@ import { createRequire } from "node:module"; import os from "node:os"; import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime"; +import { readPluginPackageVersion } from "openclaw/plugin-sdk/extension-shared"; import { fetchWithSsrFGuard } from "openclaw/plugin-sdk/ssrf-runtime"; import { normalizeOptionalString } from "openclaw/plugin-sdk/text-runtime"; import { debugLog, debugError } from "./utils/debug-log.js"; @@ -12,26 +13,7 @@ const TOKEN_URL = "https://bots.qq.com/app/getAppAccessToken"; // Plugin User-Agent format: QQBotPlugin/{version} (Node/{nodeVersion}; {os}) const _require = createRequire(import.meta.url); -const PACKAGE_JSON_CANDIDATES = [ - "../package.json", - "./package.json", - "../../package.json", -] as const; - -function readPluginVersion(): string { - for (const candidate of PACKAGE_JSON_CANDIDATES) { - try { - const version = (_require(candidate) as { version?: unknown }).version; - if (typeof version === "string" && version.trim().length > 0) { - return version; - } - } catch { - // Ignore missing candidate paths across source and bundled layouts. - } - } - return "unknown"; -} -const _pluginVersion = readPluginVersion(); +const _pluginVersion = readPluginPackageVersion({ require: _require }); export const PLUGIN_USER_AGENT = `QQBotPlugin/${_pluginVersion} (Node/${process.versions.node}; ${os.platform()})`; // ========================================================================= diff --git a/extensions/qqbot/src/slash-commands.ts b/extensions/qqbot/src/slash-commands.ts index ead86c8ef09..c75c2c99593 100644 --- a/extensions/qqbot/src/slash-commands.ts +++ b/extensions/qqbot/src/slash-commands.ts @@ -11,33 +11,15 @@ import fs from "node:fs"; import { createRequire } from "node:module"; import path from "node:path"; import { resolveRuntimeServiceVersion } from "openclaw/plugin-sdk/cli-runtime"; +import { readPluginPackageVersion } from "openclaw/plugin-sdk/extension-shared"; import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/text-runtime"; import type { QQBotAccountConfig } from "./types.js"; import { debugLog } from "./utils/debug-log.js"; import { getHomeDir, getQQBotDataDir, isWindows } from "./utils/platform.js"; const require = createRequire(import.meta.url); -const PACKAGE_JSON_CANDIDATES = [ - "../package.json", - "./package.json", - "../../package.json", -] as const; - -function readPluginVersion(): string { - for (const candidate of PACKAGE_JSON_CANDIDATES) { - try { - const version = (require(candidate) as { version?: unknown }).version; - if (typeof version === "string" && version.trim().length > 0) { - return version; - } - } catch { - // Ignore missing candidate paths across source and bundled layouts. - } - } - return "unknown"; -} // Read the package version from package.json. -const PLUGIN_VERSION = readPluginVersion(); +const PLUGIN_VERSION = readPluginPackageVersion({ require }); const QQBOT_PLUGIN_GITHUB_URL = "https://github.com/openclaw/openclaw/tree/main/extensions/qqbot"; const QQBOT_UPGRADE_GUIDE_URL = "https://q.qq.com/qqbot/openclaw/upgrade.html"; diff --git a/src/plugin-sdk/extension-shared.ts b/src/plugin-sdk/extension-shared.ts index 5dd830a10ca..98eec401b8d 100644 --- a/src/plugin-sdk/extension-shared.ts +++ b/src/plugin-sdk/extension-shared.ts @@ -135,6 +135,32 @@ export function createDeferred() { return { promise, resolve, reject }; } +const DEFAULT_PACKAGE_JSON_VERSION_CANDIDATES = [ + "../package.json", + "./package.json", + "../../package.json", +] as const; + +type PackageJsonRequire = (id: string) => unknown; + +export function readPluginPackageVersion(params: { + require: PackageJsonRequire; + candidates?: readonly string[]; + fallback?: string; +}): string { + for (const candidate of params.candidates ?? DEFAULT_PACKAGE_JSON_VERSION_CANDIDATES) { + try { + const version = (params.require(candidate) as { version?: unknown }).version; + if (typeof version === "string" && version.trim().length > 0) { + return version; + } + } catch { + // Ignore missing candidate paths across source and bundled layouts. + } + } + return params.fallback ?? "unknown"; +} + let proxyAgentConstructorPromise: Promise | null = null; async function loadProxyAgentConstructor(): Promise {