openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
217 lines (216 loc) • 7.95 kB
JavaScript
import { l as normalizeOptionalString } from "./string-coerce-6kR-86XC.mjs";
import { _ as resolveClawHubBaseUrl, i as fetchClawHubJson, l as readClawHubBytes, n as createClawHubError, r as decodeClawHubResponseBody, s as parseClawHubJsonBody, v as resolveClawHubImageUrl, y as withClawHubResponse } from "./clawhub-client-BNsvuiTA.mjs";
import { t as reportClawHubInstallTelemetry } from "./clawhub-telemetry-ClX5F6Mh.mjs";
//#region src/infra/clawhub-skills.ts
const SKILL_CARD_MAX_BYTES = 262144;
const SKILL_VERIFICATION_MAX_BYTES = 67108864;
const CLAWHUB_SKILLS_SH_TRUST_STATE = "not-scanned-by-clawhub";
const CLAWHUB_SKILLS_SH_TRUST_LABEL = "Not scanned by ClawHub";
/** Marks a reference ClawHub resolves from an external source it never scanned. */
const CLAWHUB_SKILLS_SH_REF_PREFIX = "skills-sh:";
/** Source variants ClawHub resolves search results from. Anything else is unidentifiable. */
const CLAWHUB_NATIVE_SOURCE_KIND = "clawhub";
const CLAWHUB_SKILLS_SH_SOURCE_KIND = "skills-sh";
const CLAWHUB_SUPPORTED_INSTALL_KINDS = /* @__PURE__ */ new Set([
"clawhub",
"github",
"skills-sh"
]);
function buildVersionOrTagSearch(params) {
const version = normalizeOptionalString(params.version);
const ownerHandle = normalizeOptionalString(params.ownerHandle);
if (version) return {
version,
...ownerHandle ? { ownerHandle } : {}
};
const tag = normalizeOptionalString(params.tag);
if (tag) return {
tag,
...ownerHandle ? { ownerHandle } : {}
};
return ownerHandle ? { ownerHandle } : void 0;
}
async function searchClawHubSkills(params) {
const registry = resolveClawHubBaseUrl(params.baseUrl);
const query = params.query.trim();
const request = {
baseUrl: registry,
token: params.token,
timeoutMs: params.timeoutMs,
fetchImpl: params.fetchImpl
};
let entries;
if (query) entries = (await fetchClawHubJson({
...request,
path: "/api/v1/search",
search: {
q: query,
limit: params.limit ? String(params.limit) : void 0
}
})).results ?? [];
else entries = ((await fetchClawHubJson({
...request,
path: "/api/v1/trending",
search: {
kind: "skills",
limit: String(Math.min(params.limit ?? 20, 100))
}
})).items ?? []).map((entry) => ({
score: 0,
slug: entry.slug,
displayName: entry.displayName,
summary: entry.summary ?? void 0,
source: entry.source,
install: entry.install,
official: entry.official,
ownerHandle: entry.publisher?.handle,
updatedAt: entry.metrics?.updatedAt ?? void 0
}));
return entries.flatMap((entry) => {
const mapped = toClawHubSkillSearchResult(entry, registry);
return mapped ? [mapped] : [];
});
}
/**
* Records each result's own source once, here, so no consumer rebuilds it. A row whose source is
* unknown, or whose external reference is missing, is dropped rather than published under
* `@owner/slug`: that spelling would point install at a different publisher's skill.
*/
function toClawHubSkillSearchResult(entry, registry) {
const { install: _install, source: _source, ...rest } = entry;
const base = {
...rest,
registry,
icon: resolveClawHubImageUrl(entry.icon, registry)
};
const source = normalizeOptionalString(entry.source);
const installKind = normalizeOptionalString(entry.install?.kind);
const reference = normalizeOptionalString(entry.install?.reference);
if (installKind && !CLAWHUB_SUPPORTED_INSTALL_KINDS.has(installKind)) return;
switch (source) {
case CLAWHUB_SKILLS_SH_SOURCE_KIND:
if (!reference?.startsWith("skills-sh:")) return;
return {
...base,
installRef: reference,
installOnly: true,
trustState: CLAWHUB_SKILLS_SH_TRUST_STATE
};
case CLAWHUB_NATIVE_SOURCE_KIND: {
const ownerHandle = normalizeOptionalString(entry.ownerHandle);
return ownerHandle ? {
...base,
installRef: `@${ownerHandle}/${entry.slug}`
} : void 0;
}
default: return;
}
}
async function fetchClawHubSkillDetail(params) {
const detail = await fetchClawHubJson({
baseUrl: params.baseUrl,
path: `/api/v1/skills/${encodeURIComponent(params.slug)}`,
token: params.token,
timeoutMs: params.timeoutMs,
fetchImpl: params.fetchImpl,
search: params.ownerHandle ? { ownerHandle: params.ownerHandle } : void 0
});
return {
...detail,
skill: detail.skill ? {
...detail.skill,
icon: resolveClawHubImageUrl(detail.skill.icon, params.baseUrl)
} : null
};
}
async function fetchClawHubSkillInstallResolution(params) {
return await withClawHubResponse({
baseUrl: params.baseUrl,
path: `/api/v1/skills/${encodeURIComponent(params.slug)}/install`,
token: params.token,
timeoutMs: params.timeoutMs,
fetchImpl: params.fetchImpl,
search: {
ownerHandle: params.ownerHandle,
reference: params.requestedReference,
forceInstall: params.forceInstall ? "1" : void 0
}
}, async ({ response, url, hasToken }) => {
const isStructuredBlock = [
403,
409,
410,
423
].includes(response.status);
if (!response.ok && !isStructuredBlock) throw await createClawHubError(response, url, hasToken, params.timeoutMs);
return parseClawHubJsonBody(response, url, params.timeoutMs);
});
}
async function fetchClawHubSkillVerification(params) {
return await fetchClawHubJson({
baseUrl: params.baseUrl,
path: `/api/v1/skills/${encodeURIComponent(params.slug)}/verify`,
maxResponseBytes: SKILL_VERIFICATION_MAX_BYTES,
token: params.token,
skipAuth: params.skipAuth,
timeoutMs: params.timeoutMs,
fetchImpl: params.fetchImpl,
search: {
...buildVersionOrTagSearch(params),
reference: params.requestedReference
}
});
}
async function fetchClawHubSkillSecurityVerdicts(params) {
return await fetchClawHubJson({
baseUrl: params.baseUrl,
path: "/api/v1/skills/-/security-verdicts",
method: "POST",
json: { items: params.items },
token: params.token,
skipAuth: params.skipAuth,
timeoutMs: params.timeoutMs,
fetchImpl: params.fetchImpl
});
}
async function fetchClawHubSkillCard(params) {
const cardUrl = normalizeOptionalString(params.url);
const slug = normalizeOptionalString(params.slug);
if (!cardUrl && !slug) throw new Error("ClawHub skill card fetch requires a slug or card URL");
const providedToken = normalizeOptionalString(params.token);
const skipAuth = cardUrl != null && providedToken == null && new URL(cardUrl, `${resolveClawHubBaseUrl(params.baseUrl)}/`).origin !== new URL(`${resolveClawHubBaseUrl(params.baseUrl)}/`).origin;
return await withClawHubResponse({
baseUrl: params.baseUrl,
url: cardUrl,
path: slug ? `/api/v1/skills/${encodeURIComponent(slug)}/card` : void 0,
token: providedToken,
timeoutMs: params.timeoutMs,
fetchImpl: params.fetchImpl,
search: cardUrl ? void 0 : buildVersionOrTagSearch(params),
skipAuth
}, async ({ response, url, hasToken }) => {
if (!response.ok) throw await createClawHubError(response, url, hasToken, params.timeoutMs);
const bytes = await readClawHubBytes({
response,
maxBytes: SKILL_CARD_MAX_BYTES,
timeoutMs: params.timeoutMs,
resourceLabel: slug ? `skill card for ${slug}` : `skill card at ${url.pathname}`
});
return decodeClawHubResponseBody(bytes);
});
}
async function reportClawHubSkillInstallTelemetry(params) {
return await reportClawHubInstallTelemetry(params, () => {
const slug = params.slug.trim();
return slug ? {
event: "install",
slug,
...params.ownerHandle ? { ownerHandle: params.ownerHandle } : {},
...params.requestedReference ? { reference: params.requestedReference } : {},
...params.trustState ? { trustState: params.trustState } : {},
version: params.version ?? void 0
} : void 0;
});
}
//#endregion
export { fetchClawHubSkillDetail as a, fetchClawHubSkillVerification as c, fetchClawHubSkillCard as i, reportClawHubSkillInstallTelemetry as l, CLAWHUB_SKILLS_SH_TRUST_LABEL as n, fetchClawHubSkillInstallResolution as o, CLAWHUB_SKILLS_SH_TRUST_STATE as r, fetchClawHubSkillSecurityVerdicts as s, CLAWHUB_SKILLS_SH_REF_PREFIX as t, searchClawHubSkills as u };