test(release): wait for bundled runtime commands

This commit is contained in:
Peter Steinberger
2026-05-31 14:09:18 +01:00
parent 318cae1500
commit 100dd79468
2 changed files with 37 additions and 11 deletions

View File

@@ -698,14 +698,7 @@ async function runManifestProbes(plan, options) {
}
}
if (plan.runtimeSlashAliases.length > 0 && plan.activeInThisProbe) {
const commands = await retryRpcCall(
"commands.list",
{ scope: "both", includeArgs: true },
options,
);
for (const alias of plan.runtimeSlashAliases) {
assertCommandVisible(commands, alias);
}
await retryCommandsListWithAliases(plan.runtimeSlashAliases, options);
} else if (plan.runtimeSlashAliases.length > 0) {
console.log(
`Runtime slash command smoke skipped for ${options.pluginId}: plugin is lazy in this probe`,
@@ -741,10 +734,10 @@ function isChannelVisible(payload, channel) {
return false;
}
function assertCommandVisible(payload, alias) {
export function isCommandVisible(payload, alias) {
const expected = alias.replace(/^\//u, "").toLowerCase();
const commands = Array.isArray(payload.commands) ? payload.commands : [];
const found = commands.some((command) => {
return commands.some((command) => {
const names = [
command?.name,
command?.nativeName,
@@ -754,13 +747,34 @@ function assertCommandVisible(payload, alias) {
.map((value) => value.replace(/^\//u, "").toLowerCase());
return names.includes(expected);
});
if (!found) {
}
function assertCommandVisible(payload, alias) {
const expected = alias.replace(/^\//u, "").toLowerCase();
if (!isCommandVisible(payload, alias)) {
throw new Error(
`commands.list did not include /${expected}: ${JSON.stringify(payload).slice(0, 2000)}`,
);
}
}
async function retryCommandsListWithAliases(aliases, options) {
const started = Date.now();
let commands;
while (Date.now() - started < COMMAND_TIMEOUT_MS) {
commands = await retryRpcCall("commands.list", { scope: "both", includeArgs: true }, options);
const missing = aliases.filter((alias) => !isCommandVisible(commands, alias));
if (missing.length === 0) {
return commands;
}
await delay(500);
}
for (const alias of aliases) {
assertCommandVisible(commands, alias);
}
return commands;
}
function assertToolVisible(payload, tool) {
const groups = Array.isArray(payload.groups) ? payload.groups : [];
const found = groups.some((group) =>

View File

@@ -176,6 +176,18 @@ describe("bundled plugin install/uninstall probe", () => {
expect(second).toEqual({ text: "fghij", truncatedChars: 5 });
});
it("matches runtime slash aliases across command list surfaces", async () => {
const runtimeSmoke = await import(pathToFileURL(runtimeSmokePath).href);
const payload = {
commands: [{ name: "voicecall" }, { nativeName: "phone" }, { textAliases: ["/pair"] }],
};
expect(runtimeSmoke.isCommandVisible(payload, "/voicecall")).toBe(true);
expect(runtimeSmoke.isCommandVisible(payload, "/phone")).toBe(true);
expect(runtimeSmoke.isCommandVisible(payload, "/pair")).toBe(true);
expect(runtimeSmoke.isCommandVisible(payload, "/missing")).toBe(false);
});
it("rejects loose runtime output limit env values instead of parsing prefixes", async () => {
const runtimeSmoke = await importRuntimeSmokeWithEnv({
OPENCLAW_BUNDLED_PLUGIN_RUNTIME_OUTPUT_CHARS: "5chars",