mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 17:40:44 +00:00
refactor: mark implicit startup sidecars deprecated
This commit is contained in:
@@ -206,6 +206,21 @@ export const PLUGIN_COMPAT_RECORDS = [
|
||||
diagnostics: ["activation plan compat reason"],
|
||||
tests: ["src/plugins/activation-planner.test.ts"],
|
||||
},
|
||||
{
|
||||
code: "legacy-implicit-startup-sidecar",
|
||||
status: "deprecated",
|
||||
owner: "plugin-execution",
|
||||
introduced: "2026-04-28",
|
||||
deprecated: "2026-04-28",
|
||||
warningStarts: "2026-04-28",
|
||||
removeAfter: "2026-07-28",
|
||||
replacement:
|
||||
"`activation.onStartup: true` for startup work or `activation.onStartup: false` for inert plugins",
|
||||
docsPath: "/plugins/manifest",
|
||||
surfaces: ["Gateway startup plugin planning", "openclaw.plugin.json activation"],
|
||||
diagnostics: ["plugin compatibility notice"],
|
||||
tests: ["src/plugins/channel-plugin-ids.test.ts", "src/plugins/installed-plugin-index.test.ts"],
|
||||
},
|
||||
{
|
||||
code: "activation-provider-hint",
|
||||
status: "active",
|
||||
|
||||
@@ -49,10 +49,22 @@ function hasRuntimeContractSurface(record: PluginManifestRecord): boolean {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Compatibility classification for plugins that predate explicit
|
||||
* `activation.onStartup`. Every plugin manifest should move to an explicit
|
||||
* startup decision so Gateway boot can avoid importing inert plugins.
|
||||
*/
|
||||
function isLegacyImplicitStartupSidecar(record: PluginManifestRecord): boolean {
|
||||
return (
|
||||
record.channels.length === 0 &&
|
||||
!hasRuntimeContractSurface(record) &&
|
||||
record.activation?.onStartup === undefined
|
||||
);
|
||||
}
|
||||
|
||||
function buildStartupInfo(record: PluginManifestRecord): InstalledPluginStartupInfo {
|
||||
const channels = record.channels ?? [];
|
||||
return {
|
||||
sidecar: channels.length === 0 && !hasRuntimeContractSurface(record),
|
||||
sidecar: record.activation?.onStartup === true || isLegacyImplicitStartupSidecar(record),
|
||||
memory: hasKind(record.kind, "memory"),
|
||||
deferConfiguredChannelFullLoadUntilAfterListen:
|
||||
record.startupDeferConfiguredChannelFullLoadUntilAfterListen === true,
|
||||
@@ -65,6 +77,9 @@ function buildStartupInfo(record: PluginManifestRecord): InstalledPluginStartupI
|
||||
|
||||
function collectCompatCodes(record: PluginManifestRecord): readonly PluginCompatCode[] {
|
||||
const codes: PluginCompatCode[] = [];
|
||||
if (isLegacyImplicitStartupSidecar(record)) {
|
||||
codes.push("legacy-implicit-startup-sidecar");
|
||||
}
|
||||
if (record.providerAuthEnvVars && Object.keys(record.providerAuthEnvVars).length > 0) {
|
||||
codes.push("provider-auth-env-vars");
|
||||
}
|
||||
|
||||
@@ -263,6 +263,90 @@ describe("installed plugin index", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("tags deprecated implicit startup sidecars for legacy plugins", () => {
|
||||
const rootDir = makeTempDir();
|
||||
writeRuntimeEntry(rootDir);
|
||||
writePluginManifest(rootDir, {
|
||||
id: "legacy-sidecar",
|
||||
configSchema: { type: "object" },
|
||||
});
|
||||
|
||||
const index = loadInstalledPluginIndex({
|
||||
candidates: [
|
||||
createPluginCandidate({
|
||||
rootDir,
|
||||
}),
|
||||
],
|
||||
env: hermeticEnv(),
|
||||
});
|
||||
|
||||
expect(index.plugins[0]).toMatchObject({
|
||||
pluginId: "legacy-sidecar",
|
||||
startup: {
|
||||
sidecar: true,
|
||||
},
|
||||
compat: ["legacy-implicit-startup-sidecar"],
|
||||
});
|
||||
});
|
||||
|
||||
it("does not classify or tag explicit startup opt-outs as deprecated implicit sidecars", () => {
|
||||
const rootDir = makeTempDir();
|
||||
writeRuntimeEntry(rootDir);
|
||||
writePluginManifest(rootDir, {
|
||||
id: "modern-inert",
|
||||
activation: {
|
||||
onStartup: false,
|
||||
},
|
||||
configSchema: { type: "object" },
|
||||
});
|
||||
|
||||
const index = loadInstalledPluginIndex({
|
||||
candidates: [
|
||||
createPluginCandidate({
|
||||
rootDir,
|
||||
}),
|
||||
],
|
||||
env: hermeticEnv(),
|
||||
});
|
||||
|
||||
expect(index.plugins[0]).toMatchObject({
|
||||
pluginId: "modern-inert",
|
||||
startup: {
|
||||
sidecar: false,
|
||||
},
|
||||
compat: [],
|
||||
});
|
||||
});
|
||||
|
||||
it("classifies explicit startup activation as a gateway startup sidecar", () => {
|
||||
const rootDir = makeTempDir();
|
||||
writeRuntimeEntry(rootDir);
|
||||
writePluginManifest(rootDir, {
|
||||
id: "explicit-startup-provider",
|
||||
providers: ["demo"],
|
||||
activation: {
|
||||
onStartup: true,
|
||||
},
|
||||
configSchema: { type: "object" },
|
||||
});
|
||||
|
||||
const index = loadInstalledPluginIndex({
|
||||
candidates: [
|
||||
createPluginCandidate({
|
||||
rootDir,
|
||||
}),
|
||||
],
|
||||
env: hermeticEnv(),
|
||||
});
|
||||
|
||||
expect(index.plugins[0]).toMatchObject({
|
||||
pluginId: "explicit-startup-provider",
|
||||
startup: {
|
||||
sidecar: true,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it("keeps bundle format metadata needed for manifest reconstruction", () => {
|
||||
const rootDir = makeTempDir();
|
||||
fs.mkdirSync(path.join(rootDir, ".claude-plugin"), { recursive: true });
|
||||
|
||||
Reference in New Issue
Block a user