mirror of
https://github.com/openclaw/openclaw.git
synced 2026-07-22 17:07:28 +02:00
skills: normalize capability aliases and shape variants
This commit is contained in:
@@ -104,14 +104,137 @@ export function resolveOpenClawMetadata(
|
||||
}
|
||||
|
||||
function parseCapabilities(raw: unknown): SkillCapability[] | undefined {
|
||||
const list = normalizeStringList(raw);
|
||||
if (list.length === 0) {
|
||||
const canonical = new Set<SkillCapability>();
|
||||
const names = extractCapabilityNames(raw);
|
||||
for (const name of names) {
|
||||
const normalized = normalizeCapabilityName(name);
|
||||
if (normalized) {
|
||||
canonical.add(normalized);
|
||||
}
|
||||
}
|
||||
return canonical.size > 0 ? [...canonical] : undefined;
|
||||
}
|
||||
|
||||
const CAPABILITY_SET = new Set<string>(SKILL_CAPABILITIES as readonly string[]);
|
||||
|
||||
// Accept common naming used across Codex/Claude/Cursor and map to canonical OpenClaw capabilities.
|
||||
const CAPABILITY_ALIASES: Record<string, SkillCapability> = {
|
||||
// shell
|
||||
bash: "shell",
|
||||
command: "shell",
|
||||
commands: "shell",
|
||||
exec: "shell",
|
||||
process: "shell",
|
||||
shell: "shell",
|
||||
terminal: "shell",
|
||||
"shell.exec": "shell",
|
||||
"shell.execute": "shell",
|
||||
shell_exec: "shell",
|
||||
|
||||
// filesystem
|
||||
"apply-patch": "filesystem",
|
||||
apply_patch: "filesystem",
|
||||
edit: "filesystem",
|
||||
file: "filesystem",
|
||||
files: "filesystem",
|
||||
filesystem: "filesystem",
|
||||
fs: "filesystem",
|
||||
write: "filesystem",
|
||||
|
||||
// network
|
||||
fetch: "network",
|
||||
http: "network",
|
||||
mcp: "network",
|
||||
network: "network",
|
||||
web: "network",
|
||||
webfetch: "network",
|
||||
"web-fetch": "network",
|
||||
web_fetch: "network",
|
||||
web_search: "network",
|
||||
"web.search": "network",
|
||||
"network.fetch": "network",
|
||||
"network.search": "network",
|
||||
|
||||
// browser / computer-use style
|
||||
browser: "browser",
|
||||
"computer-use": "browser",
|
||||
computer_use: "browser",
|
||||
gui: "browser",
|
||||
screen: "browser",
|
||||
ui: "browser",
|
||||
|
||||
// sessions / orchestration
|
||||
delegate: "sessions",
|
||||
orchestration: "sessions",
|
||||
sessions: "sessions",
|
||||
sessions_send: "sessions",
|
||||
sessions_spawn: "sessions",
|
||||
subagent: "sessions",
|
||||
subagents: "sessions",
|
||||
|
||||
// messaging
|
||||
chat: "messaging",
|
||||
message: "messaging",
|
||||
messages: "messaging",
|
||||
messaging: "messaging",
|
||||
|
||||
// scheduling
|
||||
cron: "scheduling",
|
||||
schedule: "scheduling",
|
||||
scheduler: "scheduling",
|
||||
scheduling: "scheduling",
|
||||
timer: "scheduling",
|
||||
};
|
||||
|
||||
function normalizeCapabilityName(raw: string): SkillCapability | undefined {
|
||||
const key = raw.trim().toLowerCase();
|
||||
if (!key) {
|
||||
return undefined;
|
||||
}
|
||||
const valid = list.filter((v): v is SkillCapability =>
|
||||
(SKILL_CAPABILITIES as readonly string[]).includes(v),
|
||||
);
|
||||
return valid.length > 0 ? valid : undefined;
|
||||
if (CAPABILITY_SET.has(key)) {
|
||||
return key as SkillCapability;
|
||||
}
|
||||
const alias = CAPABILITY_ALIASES[key];
|
||||
if (alias) {
|
||||
return alias;
|
||||
}
|
||||
const firstSegment = key.split(/[._:-]/)[0];
|
||||
if (CAPABILITY_SET.has(firstSegment)) {
|
||||
return firstSegment as SkillCapability;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function extractCapabilityNames(raw: unknown): string[] {
|
||||
if (!raw) {
|
||||
return [];
|
||||
}
|
||||
if (typeof raw === "string") {
|
||||
return normalizeStringList(raw);
|
||||
}
|
||||
if (Array.isArray(raw)) {
|
||||
const names: string[] = [];
|
||||
for (const entry of raw) {
|
||||
if (typeof entry === "string") {
|
||||
names.push(entry);
|
||||
continue;
|
||||
}
|
||||
if (entry && typeof entry === "object" && !Array.isArray(entry)) {
|
||||
const obj = entry as Record<string, unknown>;
|
||||
const candidate = [obj.name, obj.type, obj.id, obj.capability].find(
|
||||
(value) => typeof value === "string",
|
||||
);
|
||||
if (typeof candidate === "string") {
|
||||
names.push(candidate);
|
||||
}
|
||||
}
|
||||
}
|
||||
return names;
|
||||
}
|
||||
if (typeof raw === "object") {
|
||||
return Object.keys(raw as Record<string, unknown>);
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
export function resolveSkillInvocationPolicy(
|
||||
|
||||
Reference in New Issue
Block a user