From 3a941d8a6dfbaf8f67111577db604ded18619dbc Mon Sep 17 00:00:00 2001 From: sunlei Date: Thu, 18 Jun 2026 02:29:32 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E5=8E=9F=E7=94=9F=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E6=8F=92=E4=BB=B6=E5=8C=85manifest=E5=A5=91=E7=BA=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/manifest/manifest.parser.ts | 10 ++- .../domain/manifest/manifest.types.ts | 2 + .../package/plugin-package-source.service.ts | 86 ++----------------- .../qqbot/plugin-platform/manifest.spec.ts | 17 ++++ .../plugin-package-source.spec.ts | 6 +- 5 files changed, 37 insertions(+), 84 deletions(-) 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 0922815..f890523 100644 --- a/src/modules/qqbot/plugin-platform/domain/manifest/manifest.parser.ts +++ b/src/modules/qqbot/plugin-platform/domain/manifest/manifest.parser.ts @@ -597,18 +597,21 @@ export const parseQqbotPluginManifest = ( ]); } - const pluginKey = getString(manifestLike, 'pluginKey') || ''; + const pluginKey = + getString(manifestLike, 'key') || getString(manifestLike, 'pluginKey') || ''; + const pluginKeyPath = getString(manifestLike, 'key') ? 'key' : 'pluginKey'; if (!pluginKeyPattern.test(pluginKey)) { pushIssue( issues, 'INVALID_PLUGIN_KEY', - 'pluginKey', + pluginKeyPath, 'Plugin key must be lower-case kebab-case.', ); } const version = getString(manifestLike, 'version') || ''; - const minApiSdkVersion = getString(manifestLike, 'minApiSdkVersion') || ''; + const minApiSdkVersion = + getString(manifestLike, 'minApiSdkVersion') || '1.0.0'; requireSemver(version, 'version', issues); requireSemver(minApiSdkVersion, 'minApiSdkVersion', issues); @@ -633,6 +636,7 @@ export const parseQqbotPluginManifest = ( 'permissions', issues, ), + key: pluginKey, pluginKey, runtime: parseRuntime(manifestLike, issues), tasks: parseTasks(manifestLike, issues), 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 e678a61..b6e9472 100644 --- a/src/modules/qqbot/plugin-platform/domain/manifest/manifest.types.ts +++ b/src/modules/qqbot/plugin-platform/domain/manifest/manifest.types.ts @@ -13,6 +13,7 @@ export const QQBOT_PLUGIN_ALLOWED_PERMISSIONS = [ export const QQBOT_PLUGIN_WORKER_TYPES = [ 'child-process', 'node-worker', + 'thread', ] as const; export type QqbotPluginPermission = @@ -85,6 +86,7 @@ export type QqbotPluginManifest = { name: string; operations: QqbotPluginOperationManifest[]; permissions: QqbotPluginPermission[]; + key: string; pluginKey: string; runtime: QqbotPluginRuntimeManifest; tasks: QqbotPluginTaskManifest[]; diff --git a/src/modules/qqbot/plugin-platform/infrastructure/integration/package/plugin-package-source.service.ts b/src/modules/qqbot/plugin-platform/infrastructure/integration/package/plugin-package-source.service.ts index 760b26a..a6f2717 100644 --- a/src/modules/qqbot/plugin-platform/infrastructure/integration/package/plugin-package-source.service.ts +++ b/src/modules/qqbot/plugin-platform/infrastructure/integration/package/plugin-package-source.service.ts @@ -2,10 +2,7 @@ import { Injectable } from '@nestjs/common'; import { existsSync, readdirSync, readFileSync } from 'node:fs'; import { join } from 'node:path'; -import { - parseQqbotPluginManifest, - type QqbotPluginManifest, -} from '@/modules/qqbot/plugin-platform/domain/manifest'; +import { parseQqbotPluginManifest } from '@/modules/qqbot/plugin-platform/domain/manifest'; import { QqbotPluginPackagePathPolicyService } from './plugin-package-path-policy.service'; import type { QqbotPluginPackageDescriptor } from './plugin-package.types'; @@ -62,16 +59,15 @@ export class QqbotPluginPackageSourceService { controlledPackageRoot, entry, ); - const manifest = parseQqbotPluginManifest( - this.normalizeManifestForCurrentParser(manifestLike), - { pluginRoot: controlledPackageRoot }, - ); - const pluginKey = manifest.pluginKey; + const manifest = parseQqbotPluginManifest(manifestLike, { + pluginRoot: controlledPackageRoot, + }); + const pluginKey = manifest.key; return { entry: manifest.entry, entryFile, - manifest: this.attachPackageKeyAlias(manifest, pluginKey), + manifest, packageRoot: controlledPackageRoot, pluginKey, }; @@ -98,65 +94,6 @@ export class QqbotPluginPackageSourceService { return typeof manifestLike.entry === 'string' ? manifestLike.entry : ''; } - /** - * Adapts planned package manifest aliases to the parser contract currently used by the repo. - * @param manifestLike - Parsed `plugin.json` content from a QQBot plugin package. - * @returns Parser input with the package key and worker type normalized for this codebase. - */ - private normalizeManifestForCurrentParser(manifestLike: unknown): unknown { - if (!this.isRecord(manifestLike)) return manifestLike; - - const normalized: Record = { - minApiSdkVersion: '1.0.0', - ...manifestLike, - }; - const packageKey = this.readPackageKey(manifestLike); - - if (!this.readString(normalized.pluginKey) && packageKey) { - normalized.pluginKey = packageKey; - } - if (this.isRecord(manifestLike.runtime)) { - normalized.runtime = { - ...manifestLike.runtime, - workerType: - manifestLike.runtime.workerType === 'thread' - ? 'node-worker' - : manifestLike.runtime.workerType, - }; - } - - return normalized; - } - - /** - * Adds the planned `manifest.key` alias while preserving the current manifest parser type. - * @param manifest - Parsed manifest whose `pluginKey` identifies the package. - * @param pluginKey - Package key exposed to descriptor consumers and future generic workers. - * @returns Manifest object with a runtime `key` alias for descriptor compatibility. - */ - private attachPackageKeyAlias( - manifest: QqbotPluginManifest, - pluginKey: string, - ): QqbotPluginManifest { - return { - ...manifest, - key: pluginKey, - } as QqbotPluginManifest; - } - - /** - * Reads the package key from either the planned `key` field or the current `pluginKey` field. - * @param manifestLike - Parsed `plugin.json` object that declares the package identity. - * @returns Non-empty package key when declared. - */ - private readPackageKey(manifestLike: Record): string { - return ( - this.readString(manifestLike.key) || - this.readString(manifestLike.pluginKey) || - '' - ); - } - /** * Narrows JSON values to object records before reading manifest fields. * @param value - Parsed JSON value from a QQBot plugin package manifest. @@ -165,15 +102,4 @@ export class QqbotPluginPackageSourceService { private isRecord(value: unknown): value is Record { return !!value && typeof value === 'object' && !Array.isArray(value); } - - /** - * Normalizes string manifest fields used by package discovery. - * @param value - Raw JSON field value read from `plugin.json`. - * @returns Trimmed string when the field is non-empty. - */ - private readString(value: unknown): string | undefined { - return typeof value === 'string' && value.trim() - ? value.trim() - : undefined; - } } diff --git a/test/modules/qqbot/plugin-platform/manifest.spec.ts b/test/modules/qqbot/plugin-platform/manifest.spec.ts index aa9933f..4e5c27c 100644 --- a/test/modules/qqbot/plugin-platform/manifest.spec.ts +++ b/test/modules/qqbot/plugin-platform/manifest.spec.ts @@ -176,6 +176,23 @@ describe('QQBot plugin manifest contract', () => { ]); }); + it('accepts package key and thread worker type without platform transfer shims', () => { + const validManifest = createValidManifest(); + const manifest = parseQqbotPluginManifest({ + ...validManifest, + key: 'sample-plugin', + pluginKey: undefined, + runtime: { + ...validManifest.runtime, + workerType: 'thread', + }, + }); + + expect(manifest.key).toBe('sample-plugin'); + expect(manifest.pluginKey).toBe('sample-plugin'); + expect(manifest.runtime.workerType).toBe('thread'); + }); + it('rejects unknown permissions from both plugin and operation scopes', () => { const manifest = createValidManifest(); manifest.permissions = ['qqbot.send', 'host.env.read']; diff --git a/test/modules/qqbot/plugin-platform/plugin-package-source.spec.ts b/test/modules/qqbot/plugin-platform/plugin-package-source.spec.ts index 005d4b8..f2688f1 100644 --- a/test/modules/qqbot/plugin-platform/plugin-package-source.spec.ts +++ b/test/modules/qqbot/plugin-platform/plugin-package-source.spec.ts @@ -51,7 +51,11 @@ describe('QqbotPluginPackageSourceService', () => { expect.objectContaining({ entry: 'src/index.ts', entryFile: join(packageRoot, 'src', 'index.ts'), - manifest: expect.objectContaining({ key: 'sample' }), + manifest: expect.objectContaining({ + key: 'sample', + pluginKey: 'sample', + runtime: expect.objectContaining({ workerType: 'thread' }), + }), packageRoot, pluginKey: 'sample', }),