mirror of
https://github.com/moltbot/moltbot.git
synced 2026-05-13 23:56:07 +00:00
Summary: - clarify CLI diagnostics when an unknown subcommand is actually a plugin agent tool - route early proxy-preflight misses through the same policy helper - refresh bundled sidecar update fixtures for current package ownership Verification: - pnpm test src/cli/run-main.test.ts src/cli/run-main.exit.test.ts src/plugins/manifest-command-aliases.test.ts - pnpm test src/infra/update-global.test.ts src/infra/update-runner.test.ts - pnpm exec oxfmt --check --threads=1 CHANGELOG.md src/cli/run-main-policy.ts src/cli/run-main.ts src/cli/run-main.test.ts src/cli/run-main.exit.test.ts src/plugins/manifest-command-aliases.ts src/plugins/manifest-command-aliases.runtime.ts src/plugins/manifest-command-aliases.test.ts - pnpm build - live temp lossless-claw manifest: pnpm openclaw lcm_recent emits the agent-tool diagnostic and no plugins.allow suggestion Co-authored-by: 100yenadmin <100yenadmin+agent-77214@100yen.org>
116 lines
3.9 KiB
TypeScript
116 lines
3.9 KiB
TypeScript
import type { OpenClawConfig } from "../config/types.openclaw.js";
|
|
import { normalizeOptionalLowercaseString } from "../shared/string-coerce.js";
|
|
import {
|
|
resolveManifestCommandAliasOwnerInRegistry,
|
|
resolveManifestToolOwnerInRegistry,
|
|
type PluginManifestCommandAliasRegistry,
|
|
type PluginManifestCommandAliasRecord,
|
|
type PluginManifestToolOwnerRecord,
|
|
} from "./manifest-command-aliases.js";
|
|
import {
|
|
isManifestPluginAvailableForControlPlane,
|
|
loadManifestMetadataRegistry,
|
|
loadManifestMetadataSnapshot,
|
|
} from "./manifest-contract-eligibility.js";
|
|
import { hasManifestToolAvailability } from "./manifest-tool-availability.js";
|
|
|
|
export function resolveManifestCommandAliasOwner(params: {
|
|
command: string | undefined;
|
|
config?: OpenClawConfig;
|
|
workspaceDir?: string;
|
|
env?: NodeJS.ProcessEnv;
|
|
registry?: PluginManifestCommandAliasRegistry;
|
|
}): PluginManifestCommandAliasRecord | undefined {
|
|
const registry =
|
|
params.registry ??
|
|
loadManifestMetadataRegistry({
|
|
config: params.config,
|
|
workspaceDir: params.workspaceDir,
|
|
env: params.env,
|
|
}).manifestRegistry;
|
|
return resolveManifestCommandAliasOwnerInRegistry({
|
|
command: params.command,
|
|
registry,
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Resolve which plugin owns an agent-tool name, applying control-plane
|
|
* availability filters so disabled/denied plugins are not falsely attributed.
|
|
*
|
|
* Behavior:
|
|
* - Walks the full manifest snapshot (not the lighter-weight registry view) so
|
|
* per-tool `configSignals`/`authSignals` are visible.
|
|
* - Skips plugins that fail `isManifestPluginAvailableForControlPlane`
|
|
* (`plugins.allow` / `plugins.deny` / `plugins.entries[id].enabled` /
|
|
* installed-index).
|
|
* - For matched tools, runs `hasManifestToolAvailability` to check the
|
|
* tool's own configSignals (e.g. Feishu's `appId`/`appSecret` gate).
|
|
* - Reports `availability: "loaded"` when both filters pass, enough for a
|
|
* direct "available from this plugin" diagnostic.
|
|
* - Reports `availability: "manifest-only"` when the manifest declares
|
|
* ownership but availability is not provable from manifest alone (e.g.
|
|
* per-account `enabled` flags or per-tool toggles that are runtime-only).
|
|
* Caller should soften the wording to "may be provided by".
|
|
*
|
|
* Falls back to the pure registry walk only when an explicit registry is
|
|
* supplied (no snapshot to filter against).
|
|
*/
|
|
export function resolveManifestToolOwner(params: {
|
|
toolName: string | undefined;
|
|
config?: OpenClawConfig;
|
|
workspaceDir?: string;
|
|
env?: NodeJS.ProcessEnv;
|
|
registry?: PluginManifestCommandAliasRegistry;
|
|
}): PluginManifestToolOwnerRecord | undefined {
|
|
if (params.registry) {
|
|
return resolveManifestToolOwnerInRegistry({
|
|
toolName: params.toolName,
|
|
registry: params.registry,
|
|
});
|
|
}
|
|
const normalizedToolName = normalizeOptionalLowercaseString(params.toolName);
|
|
if (!normalizedToolName) {
|
|
return undefined;
|
|
}
|
|
const snapshot = loadManifestMetadataSnapshot({
|
|
config: params.config,
|
|
workspaceDir: params.workspaceDir,
|
|
env: params.env,
|
|
});
|
|
const env = params.env ?? process.env;
|
|
for (const plugin of snapshot.plugins) {
|
|
const tools = plugin.contracts?.tools;
|
|
if (!tools || tools.length === 0) {
|
|
continue;
|
|
}
|
|
const match = tools.find(
|
|
(entry) => normalizeOptionalLowercaseString(entry) === normalizedToolName,
|
|
);
|
|
if (!match) {
|
|
continue;
|
|
}
|
|
const pluginAvailable = isManifestPluginAvailableForControlPlane({
|
|
snapshot,
|
|
plugin,
|
|
config: params.config,
|
|
});
|
|
if (!pluginAvailable) {
|
|
// Plugin is denied/disabled/uninstalled; do not attribute this tool to it.
|
|
continue;
|
|
}
|
|
const toolAvailable = hasManifestToolAvailability({
|
|
plugin,
|
|
toolNames: [match],
|
|
config: params.config,
|
|
env,
|
|
});
|
|
return {
|
|
toolName: match,
|
|
pluginId: plugin.id,
|
|
availability: toolAvailable ? "loaded" : "manifest-only",
|
|
};
|
|
}
|
|
return undefined;
|
|
}
|