

























@@ -8,6 +8,7 @@ import {
88resolvePackageExtensionEntries,
99} from "../plugins/manifest.js";
1010import { defaultRuntime } from "../runtime.js";
11+import { isRecord } from "../utils.js";
11121213type JsonObject = Record<string, unknown>;
1314@@ -116,9 +117,19 @@ export async function loadToolPlugin(params: {
116117export function buildToolPluginManifest(params: {
117118metadata: ToolPluginMetadata;
118119packageManifest: JsonObject;
120+existingManifest?: JsonObject;
119121}): JsonObject {
120-const optionalTools = params.metadata.tools.filter((tool) => tool.optional);
122+const toolMetadata = buildToolPluginToolMetadata(params.metadata, params.existingManifest);
123+const existingContracts = isRecord(params.existingManifest?.contracts)
124+ ? params.existingManifest.contracts
125+ : {};
126+const {
127+contracts: _existingContracts,
128+toolMetadata: _existingToolMetadata,
129+ ...existingManifestFields
130+} = params.existingManifest ?? {};
121131return {
132+ ...existingManifestFields,
122133id: params.metadata.id,
123134name: params.metadata.name,
124135description: params.metadata.description,
@@ -127,18 +138,35 @@ export function buildToolPluginManifest(params: {
127138configSchema: params.metadata.configSchema,
128139activation: params.metadata.activation,
129140contracts: {
141+ ...existingContracts,
130142tools: params.metadata.tools.map((tool) => tool.name),
131143},
132- ...(optionalTools.length > 0
133- ? {
134-toolMetadata: Object.fromEntries(
135-optionalTools.map((tool) => [tool.name, { optional: true }]),
136-),
137-}
138- : {}),
144+ ...(toolMetadata ? { toolMetadata } : {}),
139145};
140146}
141147148+function buildToolPluginToolMetadata(
149+metadata: ToolPluginMetadata,
150+existingManifest: JsonObject | undefined,
151+): Record<string, unknown> | undefined {
152+const existingToolMetadata = isRecord(existingManifest?.toolMetadata)
153+ ? existingManifest.toolMetadata
154+ : {};
155+const nextEntries = metadata.tools
156+.map((tool) => {
157+const existingValue = existingToolMetadata[tool.name];
158+const existing = isRecord(existingValue) ? { ...existingValue } : {};
159+if (tool.optional) {
160+existing.optional = true;
161+} else {
162+delete existing.optional;
163+}
164+return [tool.name, existing] as const;
165+})
166+.filter(([, value]) => Object.keys(value).length > 0);
167+return nextEntries.length > 0 ? Object.fromEntries(nextEntries) : undefined;
168+}
169+142170export function buildToolPluginPackageManifest(params: {
143171packageManifest: JsonObject;
144172entry: string;
@@ -168,6 +196,7 @@ export function validateToolPluginProject(params: {
168196const expectedManifest = buildToolPluginManifest({
169197metadata: params.metadata,
170198packageManifest: params.packageManifest,
199+existingManifest: params.manifest,
171200});
172201if (JSON.stringify(params.manifest) !== JSON.stringify(expectedManifest)) {
173202errors.push("openclaw.plugin.json generated metadata is stale. Run openclaw plugins build.");
@@ -217,15 +246,19 @@ export async function runPluginsBuildCommand(opts: PluginsBuildOptions): Promise
217246const packagePath = path.join(rootDir, "package.json");
218247const packageManifest = readPackageManifest(rootDir);
219248const { metadata } = await loadToolPlugin({ rootDir, entryPath });
220-const manifest = buildToolPluginManifest({ metadata, packageManifest });
249+const manifestPath = path.join(rootDir, PLUGIN_MANIFEST_FILENAME);
250+const currentManifest = fs.existsSync(manifestPath) ? readJsonFile(manifestPath) : undefined;
251+const manifest = buildToolPluginManifest({
252+ metadata,
253+ packageManifest,
254+existingManifest: currentManifest,
255+});
221256const nextPackageManifest = buildToolPluginPackageManifest({
222257 packageManifest,
223258entry: entryRelative,
224259});
225-const manifestPath = path.join(rootDir, PLUGIN_MANIFEST_FILENAME);
226260227261if (opts.check) {
228-const currentManifest = fs.existsSync(manifestPath) ? readJsonFile(manifestPath) : undefined;
229262const currentPackage = readJsonFile(packagePath);
230263if (
231264JSON.stringify(currentManifest) !== JSON.stringify(manifest) ||
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。