From 374c1ba0deeb2e8c0fe9b25fcd8474289cae1005 Mon Sep 17 00:00:00 2001 From: sunlei Date: Thu, 18 Jun 2026 01:59:34 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=94=AF=E6=8C=81=E6=8F=92=E4=BB=B6?= =?UTF-8?q?=E5=A3=B0=E6=98=8E=E8=BF=90=E8=A1=8C=E6=97=B6=E9=85=8D=E7=BD=AE?= =?UTF-8?q?=E9=94=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/manifest/manifest.parser.ts | 23 +++++++++++++++++++ .../domain/manifest/manifest.types.ts | 1 + .../qqbot/plugin-platform/manifest.spec.ts | 21 +++++++++++++++++ 3 files changed, 45 insertions(+) diff --git a/src/modules/qqbot/plugin-platform/domain/manifest/manifest.parser.ts b/src/modules/qqbot/plugin-platform/domain/manifest/manifest.parser.ts index 4c723a3..0922815 100644 --- a/src/modules/qqbot/plugin-platform/domain/manifest/manifest.parser.ts +++ b/src/modules/qqbot/plugin-platform/domain/manifest/manifest.parser.ts @@ -82,6 +82,28 @@ const getStringArray = ( .filter(Boolean); }; +/** + * Normalizes config keys declared by a plugin package manifest. + * + * @param rawKeys - Manifest-provided values from `runtime.configKeys`; these are package-owned + * names used by the generic host to preload configuration without hard-coding plugin keys. + * @returns Unique non-empty config keys in declaration order. + */ +function parseConfigKeys(rawKeys: unknown): string[] { + if (!Array.isArray(rawKeys)) { + return []; + } + + return Array.from( + new Set( + rawKeys + .filter((key): key is string => typeof key === 'string') + .map((key) => key.trim()) + .filter((key) => key.length > 0), + ), + ); +} + /** * 查询 QQBot 插件平台数据。 * @param source - source 输入;限定 插件平台查询范围。 @@ -276,6 +298,7 @@ const parseRuntime = ( } return { + configKeys: parseConfigKeys(runtime.configKeys), maxConcurrency: maxConcurrency || 1, memoryMb: memoryMb || 128, timeoutMs: timeoutMs || 1000, diff --git a/src/modules/qqbot/plugin-platform/domain/manifest/manifest.types.ts b/src/modules/qqbot/plugin-platform/domain/manifest/manifest.types.ts index 8e261e3..e678a61 100644 --- a/src/modules/qqbot/plugin-platform/domain/manifest/manifest.types.ts +++ b/src/modules/qqbot/plugin-platform/domain/manifest/manifest.types.ts @@ -21,6 +21,7 @@ export type QqbotPluginPermission = export type QqbotPluginWorkerType = (typeof QQBOT_PLUGIN_WORKER_TYPES)[number]; export type QqbotPluginRuntimeManifest = { + configKeys: string[]; maxConcurrency: number; memoryMb: number; timeoutMs: number; diff --git a/test/modules/qqbot/plugin-platform/manifest.spec.ts b/test/modules/qqbot/plugin-platform/manifest.spec.ts index dcc91a1..aa9933f 100644 --- a/test/modules/qqbot/plugin-platform/manifest.spec.ts +++ b/test/modules/qqbot/plugin-platform/manifest.spec.ts @@ -155,6 +155,27 @@ describe('QQBot plugin manifest contract', () => { ); }); + it('normalizes runtime config keys without platform-owned plugin knowledge', () => { + const validManifest = createValidManifest(); + const manifest = parseQqbotPluginManifest({ + ...validManifest, + runtime: { + ...validManifest.runtime, + configKeys: [ + 'SAMPLE_TOKEN', + ' SAMPLE_TIMEOUT_MS ', + '', + 'SAMPLE_TOKEN', + ], + }, + }); + + expect(manifest.runtime.configKeys).toEqual([ + 'SAMPLE_TOKEN', + 'SAMPLE_TIMEOUT_MS', + ]); + }); + it('rejects unknown permissions from both plugin and operation scopes', () => { const manifest = createValidManifest(); manifest.permissions = ['qqbot.send', 'host.env.read'];