fix(release): stabilize plugin prerelease validation

This commit is contained in:
Peter Steinberger
2026-05-01 19:25:36 +01:00
parent 13c4066816
commit 73c429d24f
8 changed files with 45 additions and 16 deletions

View File

@@ -82,19 +82,26 @@ async function waitForProbeExit(params: {
throw new Error(`${label} MCP probe process still alive after run: pid=${pid} args=${args}`);
}
async function waitForAnyProbeExit(params: {
async function waitForAllProbeExits(params: {
pidsPath: string;
label: string;
timeoutMs: number;
}): Promise<number> {
}): Promise<number[]> {
const startedAt = Date.now();
let observed: number[] = [];
while (Date.now() - startedAt < params.timeoutMs) {
observed = await readProbePids(params.pidsPath);
for (const pid of observed) {
const args = await describeProbePid(pid);
if (!args || !args.includes("openclaw-cron-mcp-cleanup-probe")) {
return pid;
if (observed.length > 0) {
let allExited = true;
for (const pid of observed) {
const args = await describeProbePid(pid);
if (args?.includes("openclaw-cron-mcp-cleanup-probe")) {
allExited = false;
break;
}
}
if (allExited) {
return observed;
}
}
await delay(100);
@@ -201,7 +208,7 @@ async function runSubagentCleanupScenario(params: {
pidPath: string;
pidsPath: string;
exitPath: string;
}): Promise<{ runId: string; exitedPid: number; pids: number[] }> {
}): Promise<{ runId: string; exitedPids: number[]; pids: number[] }> {
const { gateway, pidPath, pidsPath, exitPath } = params;
await resetProbeFiles({ pidPath, pidsPath, exitPath });
@@ -238,14 +245,14 @@ async function runSubagentCleanupScenario(params: {
`subagent cleanup run did not finish ok: ${JSON.stringify(finished)}`,
);
const exitedPid = await waitForAnyProbeExit({
const exitedPids = await waitForAllProbeExits({
pidsPath,
label: "subagent",
timeoutMs: 240_000,
});
return {
runId: run.runId,
exitedPid,
exitedPids,
pids: await readProbePids(pidsPath),
};
}

View File

@@ -14,7 +14,7 @@ const READY_TIMEOUT_MS = readPositiveInt(
const RPC_TIMEOUT_MS = readPositiveInt(process.env.OPENCLAW_BUNDLED_PLUGIN_RUNTIME_RPC_MS, 60000);
const RPC_READY_TIMEOUT_MS = readPositiveInt(
process.env.OPENCLAW_BUNDLED_PLUGIN_RUNTIME_RPC_READY_MS,
90000,
210000,
);
function readPositiveInt(raw, fallback) {

View File

@@ -198,7 +198,8 @@ run_proxy_env_flow() {
printf "%s\n" "Environment=HTTP_PROXY=http://stale-proxy.local:7890"
printf "%s\n" "Environment=HTTPS_PROXY=https://stale-proxy.local:7890"
} >>"$unit_path"
if ! timeout "$command_timeout" node "$git_cli" doctor --repair --yes >"$doctor_log" 2>&1; then
if ! timeout "$command_timeout" env OPENCLAW_UPDATE_IN_PROGRESS=1 \
node "$git_cli" doctor --repair --force --yes --non-interactive >"$doctor_log" 2>&1; then
cat "$doctor_log"
exit 1
fi

View File

@@ -441,7 +441,7 @@ export function createSubagentRegistryLifecycleController(params: {
retryDeferredCompletedAnnounces(cleanupParams.runId);
};
const retireRunModeBundleMcpRuntime = (cleanupParams: {
const retireRunModeBundleMcpRuntime = async (cleanupParams: {
runId: string;
entry: SubagentRunRecord;
reason: string;
@@ -449,7 +449,7 @@ export function createSubagentRegistryLifecycleController(params: {
if (cleanupParams.entry.spawnMode === "session") {
return;
}
void retireSessionMcpRuntimeForSessionKey({
await retireSessionMcpRuntimeForSessionKey({
sessionKey: cleanupParams.entry.childSessionKey,
reason: cleanupParams.reason,
onError: (error, sessionId) => {
@@ -772,7 +772,7 @@ export function createSubagentRegistryLifecycleController(params: {
onWarn: (msg) => params.warn(msg, { runId: entry.runId }),
});
retireRunModeBundleMcpRuntime({
await retireRunModeBundleMcpRuntime({
runId: completeParams.runId,
entry,
reason: "subagent-run-complete",

View File

@@ -15,4 +15,18 @@ describe("plugin loader records", () => {
expect(record.channelIds).toEqual(["kitchen-sink-channel"]);
});
it("preserves manifest-declared provider ids before runtime registration", () => {
const record = createPluginRecord({
id: "kitchen-sink",
name: "Kitchen Sink",
source: "/tmp/kitchen-sink/index.js",
origin: "global",
enabled: true,
providerIds: ["kitchen-sink-provider"],
configSchema: false,
});
expect(record.providerIds).toEqual(["kitchen-sink-provider"]);
});
});

View File

@@ -23,6 +23,7 @@ export function createPluginRecord(params: {
activationState?: PluginActivationState;
syntheticAuthRefs?: string[];
channelIds?: readonly string[];
providerIds?: readonly string[];
configSchema: boolean;
contracts?: PluginManifestContracts;
}): PluginRecord {
@@ -50,7 +51,7 @@ export function createPluginRecord(params: {
hookNames: [],
channelIds: [...(params.channelIds ?? [])],
cliBackendIds: [],
providerIds: [],
providerIds: [...(params.providerIds ?? [])],
speechProviderIds: [],
realtimeTranscriptionProviderIds: [],
realtimeVoiceProviderIds: [],

View File

@@ -1460,6 +1460,7 @@ export function loadOpenClawPlugins(options: PluginLoadOptions = {}): PluginRegi
activationState,
syntheticAuthRefs: manifestRecord.syntheticAuthRefs,
channelIds: manifestRecord.channels,
providerIds: manifestRecord.providers,
configSchema: Boolean(manifestRecord.configSchema),
contracts: manifestRecord.contracts,
});
@@ -1496,6 +1497,7 @@ export function loadOpenClawPlugins(options: PluginLoadOptions = {}): PluginRegi
activationState,
syntheticAuthRefs: manifestRecord.syntheticAuthRefs,
channelIds: manifestRecord.channels,
providerIds: manifestRecord.providers,
configSchema: Boolean(manifestRecord.configSchema),
contracts: manifestRecord.contracts,
});
@@ -2305,6 +2307,7 @@ export async function loadOpenClawPluginCliRegistry(
activationState,
syntheticAuthRefs: manifestRecord.syntheticAuthRefs,
channelIds: manifestRecord.channels,
providerIds: manifestRecord.providers,
configSchema: Boolean(manifestRecord.configSchema),
contracts: manifestRecord.contracts,
});
@@ -2341,6 +2344,7 @@ export async function loadOpenClawPluginCliRegistry(
activationState,
syntheticAuthRefs: manifestRecord.syntheticAuthRefs,
channelIds: manifestRecord.channels,
providerIds: manifestRecord.providers,
configSchema: Boolean(manifestRecord.configSchema),
contracts: manifestRecord.contracts,
});

View File

@@ -811,7 +811,9 @@ export function createPluginRegistry(registryParams: PluginRegistryParams) {
});
return;
}
record.providerIds.push(id);
if (!record.providerIds.includes(id)) {
record.providerIds.push(id);
}
registry.providers.push({
pluginId: record.id,
pluginName: record.name,