refactor: move browser runtime seams behind plugin metadata

This commit is contained in:
Peter Steinberger
2026-04-05 23:13:03 +01:00
parent 1351bacaa4
commit 471d056e2f
44 changed files with 1441 additions and 1026 deletions

View File

@@ -1,7 +1,7 @@
import { describe, expect, it } from "vitest";
import {
rewriteUpdateFlagArgv,
resolveMissingBrowserCommandMessage,
resolveMissingPluginCommandMessage,
shouldEnsureCliPath,
shouldRegisterPrimarySubcommand,
shouldSkipPluginCommandRegistration,
@@ -138,10 +138,10 @@ describe("shouldUseRootHelpFastPath", () => {
});
});
describe("resolveMissingBrowserCommandMessage", () => {
it("explains plugins.allow misses for the browser command", () => {
describe("resolveMissingPluginCommandMessage", () => {
it("explains plugins.allow misses for a bundled plugin command", () => {
expect(
resolveMissingBrowserCommandMessage({
resolveMissingPluginCommandMessage("browser", {
plugins: {
allow: ["telegram"],
},
@@ -149,9 +149,9 @@ describe("resolveMissingBrowserCommandMessage", () => {
).toContain('`plugins.allow` excludes "browser"');
});
it("explains explicit bundled browser disablement", () => {
it("explains explicit bundled plugin disablement", () => {
expect(
resolveMissingBrowserCommandMessage({
resolveMissingPluginCommandMessage("browser", {
plugins: {
entries: {
browser: {
@@ -163,9 +163,9 @@ describe("resolveMissingBrowserCommandMessage", () => {
).toContain("plugins.entries.browser.enabled=false");
});
it("returns null when browser is already allowed", () => {
it("returns null when the bundled plugin command is already allowed", () => {
expect(
resolveMissingBrowserCommandMessage({
resolveMissingPluginCommandMessage("browser", {
plugins: {
allow: ["browser"],
},

View File

@@ -88,23 +88,32 @@ export function shouldUseRootHelpFastPath(argv: string[]): boolean {
return isRootHelpInvocation(argv);
}
export function resolveMissingBrowserCommandMessage(config?: OpenClawConfig): string | null {
export function resolveMissingPluginCommandMessage(
pluginId: string,
config?: OpenClawConfig,
): string | null {
const normalizedPluginId = pluginId.trim().toLowerCase();
if (!normalizedPluginId) {
return null;
}
const allow =
Array.isArray(config?.plugins?.allow) && config.plugins.allow.length > 0
? config.plugins.allow
.filter((entry): entry is string => typeof entry === "string")
.map((entry) => entry.trim().toLowerCase())
: [];
if (allow.length > 0 && !allow.includes("browser")) {
if (allow.length > 0 && !allow.includes(normalizedPluginId)) {
return (
'The `openclaw browser` command is unavailable because `plugins.allow` excludes "browser". ' +
'Add "browser" to `plugins.allow` if you want the bundled browser CLI and tool.'
`The \`openclaw ${normalizedPluginId}\` command is unavailable because ` +
`\`plugins.allow\` excludes "${normalizedPluginId}". Add "${normalizedPluginId}" to ` +
`\`plugins.allow\` if you want that bundled plugin CLI surface.`
);
}
if (config?.plugins?.entries?.browser?.enabled === false) {
if (config?.plugins?.entries?.[normalizedPluginId]?.enabled === false) {
return (
"The `openclaw browser` command is unavailable because `plugins.entries.browser.enabled=false`. " +
"Re-enable that entry if you want the bundled browser CLI and tool."
`The \`openclaw ${normalizedPluginId}\` command is unavailable because ` +
`\`plugins.entries.${normalizedPluginId}.enabled=false\`. Re-enable that entry if you want ` +
"the bundled plugin CLI surface."
);
}
return null;
@@ -220,13 +229,10 @@ export async function runCli(argv: string[] = process.argv) {
mode: "lazy",
primary,
});
if (
primary === "browser" &&
!program.commands.some((command) => command.name() === "browser")
) {
const browserCommandMessage = resolveMissingBrowserCommandMessage(config);
if (browserCommandMessage) {
throw new Error(browserCommandMessage);
if (primary && !program.commands.some((command) => command.name() === primary)) {
const missingPluginCommandMessage = resolveMissingPluginCommandMessage(primary, config);
if (missingPluginCommandMessage) {
throw new Error(missingPluginCommandMessage);
}
}
}