diff --git a/src/selfTest.ts b/src/selfTest.ts index 3930a65..f8bdcad 100644 --- a/src/selfTest.ts +++ b/src/selfTest.ts @@ -29,6 +29,7 @@ import { findNapcatImageGovernanceFindings, findQqbotNapcatCaptchaFlowFindings, findQqbotCommandServiceTestImportFindings, + findQqbotPluginPackageProductionPathFindings, findQqbotPluginSmokeImportFindings, findQqbotStatusBoundaryFindings, findTaskRecordGovernanceFindings, @@ -152,6 +153,59 @@ export async function runSelfTest(): Promise { ); } + const qqbotPluginProductionPathFindings = + findQqbotPluginPackageProductionPathFindings( + [ + "const DEFAULT_BUILTIN_PACKAGE_ROOT_SEGMENTS = [", + " ['src', 'modules', 'qqbot', 'plugins'],", + "];", + "private resolveEntryFile(entryFile: string) {", + " return entryFile;", + "}", + ], + { + file: "src/modules/qqbot/plugin-platform/infrastructure/integration/package/plugin-package-path-policy.service.ts", + project: "Node/kt-template-online-api", + }, + ); + if ( + !qqbotPluginProductionPathFindings.some( + (item) => + item.category === "qqbot-plugin-production-dist-root-missing", + ) || + !qqbotPluginProductionPathFindings.some( + (item) => + item.category === "qqbot-plugin-compiled-entry-fallback-missing", + ) + ) { + throw new Error("QQBot plugin production path governance self-check failed"); + } + + const qqbotPluginProductionPathValidFindings = + findQqbotPluginPackageProductionPathFindings( + [ + "const DEFAULT_BUILTIN_PACKAGE_ROOT_SEGMENTS = [", + " ['src', 'modules', 'qqbot', 'plugins'],", + " ['dist', 'modules', 'qqbot', 'plugins'],", + "];", + "private resolveCompiledEntryFile(entryFile: string): string {", + " if (entryFile.endsWith('.ts')) {", + " return `${entryFile.slice(0, -3)}.js`;", + " }", + " return entryFile;", + "}", + ], + { + file: "src/modules/qqbot/plugin-platform/infrastructure/integration/package/plugin-package-path-policy.service.ts", + project: "Node/kt-template-online-api", + }, + ); + if (qqbotPluginProductionPathValidFindings.length > 0) { + throw new Error( + "QQBot plugin production path governance valid self-check false positive", + ); + } + const qqbotStatusBoundaryFindings = [ ...findQqbotStatusBoundaryFindings( [ diff --git a/src/tools/review.ts b/src/tools/review.ts index 7c43e88..4b15a65 100644 --- a/src/tools/review.ts +++ b/src/tools/review.ts @@ -285,6 +285,71 @@ export function findQqbotPluginSmokeImportFindings( return findings; } +/** + * Finds regressions that would make descriptor-backed QQBot built-in plugins disappear from production dist images. + * @param lines - Source lines from the package path policy file being reviewed. + * @param context - Project and file identity for precise review findings. + * @returns Findings when the policy no longer supports production dist roots or compiled JavaScript entries. + */ +export function findQqbotPluginPackageProductionPathFindings( + lines: string[], + context: { + file: string; + project: string; + }, +): ReviewFinding[] { + const normalized = context.file.replaceAll("\\", "/"); + if ( + context.project !== "Node/kt-template-online-api" || + normalized !== + "src/modules/qqbot/plugin-platform/infrastructure/integration/package/plugin-package-path-policy.service.ts" + ) { + return []; + } + + const content = lines.join("\n"); + const findings: ReviewFinding[] = []; + const hasProductionDistRoot = + content.includes("'dist'") && + content.includes("'modules'") && + content.includes("'qqbot'") && + content.includes("'plugins'"); + const hasCompiledEntryFallback = + content.includes("resolveCompiledEntryFile") && + content.includes("entryFile.endsWith('.ts')") && + content.includes("}.js`"); + + if (!hasProductionDistRoot) { + findings.push({ + category: "qqbot-plugin-production-dist-root-missing", + file: context.file, + line: 1, + level: "P2", + message: + "QQBot 插件包路径策略缺少生产 dist 根,生产镜像只复制 dist 时内置插件会发现为空。", + project: context.project, + suggestion: + "默认受控根应在源码根不存在时扫描 dist/modules/qqbot/plugins,并保留源码态优先顺序。", + }); + } + + if (!hasCompiledEntryFallback) { + findings.push({ + category: "qqbot-plugin-compiled-entry-fallback-missing", + file: context.file, + line: 1, + level: "P2", + message: + "QQBot 插件 manifest 的 src/index.ts entry 缺少生产编译后 .js sibling fallback。", + project: context.project, + suggestion: + "entry 仍应保持源码结构声明,但生产运行时要在同一 package root 内解析到编译后的 src/index.js。", + }); + } + + return findings; +} + export function findQqbotStatusBoundaryFindings( lines: string[], context: { @@ -856,6 +921,10 @@ function collectProjectContentFindings( file, project: project.relativePath, }), + ...findQqbotPluginPackageProductionPathFindings(lines, { + file, + project: project.relativePath, + }), ...findQqbotStatusBoundaryFindings(lines, { file, project: project.relativePath,