mirror of
https://github.com/openclaw/clawhub.git
synced 2026-08-14 00:47:57 +00:00
* feat: add controlled catalog taxonomy and topics * refactor: limit taxonomy input to publish surfaces * fix: omit inactive official-first filter * fix: preserve unsaved catalog metadata edits * fix: enforce catalog taxonomy invariants * fix: close catalog taxonomy review gaps * fix: tolerate retired stored skill categories * fix: bound catalog metadata filter scans * fix: preserve comma-containing topic labels * fix: tolerate retired stored plugin categories * fix: ignore empty secret integration metadata * fix: honor explicit categories in related skills * fix: harden taxonomy rollout migration * fix: harden taxonomy browse pagination * fix: preserve skill topic recommendation fallback * fix: scale curated skill category browse * fix: preserve legacy plugin category filters * fix: preserve taxonomy compatibility semantics * fix: preserve legacy catalog browse links * feat: make catalog metadata editing explicit * test: update plugin manage context contract * fix: address taxonomy review findings * fix: preserve empty category publish flags * fix: preserve catalog search and publish metadata * chore: keep taxonomy migration operator-run * docs: keep taxonomy migrations operator-run * fix: reject inherited category aliases * fix: preserve normalized topic search behavior * test: cover full topic pagination cursors * feat: add catalog classification backfill --------- Co-authored-by: Patrick Erichsen <patrick.a.erichsen@gmail.com>
82 lines
3.1 KiB
JavaScript
82 lines
3.1 KiB
JavaScript
import { resolvePluginCategories } from "./catalogMetadata.js";
|
|
export { isPluginCategorySlug, PLUGIN_CATEGORY_DEFINITIONS, PLUGIN_CATEGORY_SLUGS, } from "./catalogMetadata.js";
|
|
function isRecord(value) {
|
|
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
}
|
|
function hasValues(value) {
|
|
return Array.isArray(value) && value.length > 0;
|
|
}
|
|
function hasProperties(value) {
|
|
return isRecord(value) && Object.keys(value).length > 0;
|
|
}
|
|
export function inferPluginCategoriesFromManifest(manifest) {
|
|
if (!isRecord(manifest))
|
|
return [];
|
|
const categories = [];
|
|
const add = (category) => {
|
|
if (!categories.includes(category))
|
|
categories.push(category);
|
|
};
|
|
const kinds = Array.isArray(manifest.kind) ? manifest.kind : [manifest.kind];
|
|
const contracts = isRecord(manifest.contracts) ? manifest.contracts : {};
|
|
if (hasValues(manifest.channels))
|
|
add("channels");
|
|
if (hasValues(manifest.providers) || hasValues(manifest.cliBackends))
|
|
add("models");
|
|
if (kinds.includes("memory") || hasValues(contracts.embeddingProviders))
|
|
add("memory");
|
|
if (kinds.includes("context-engine") || hasValues(contracts.memoryEmbeddingProviders)) {
|
|
add("context");
|
|
}
|
|
if (hasValues(contracts.speechProviders) ||
|
|
hasValues(contracts.realtimeTranscriptionProviders) ||
|
|
hasValues(contracts.realtimeVoiceProviders) ||
|
|
hasValues(contracts.transcriptSourceProviders)) {
|
|
add("voice");
|
|
}
|
|
if (hasValues(contracts.mediaUnderstandingProviders) ||
|
|
hasValues(contracts.imageGenerationProviders) ||
|
|
hasValues(contracts.musicGenerationProviders) ||
|
|
hasValues(contracts.videoGenerationProviders)) {
|
|
add("media");
|
|
}
|
|
if (hasValues(contracts.webFetchProviders) || hasValues(contracts.webSearchProviders)) {
|
|
add("web");
|
|
}
|
|
if (hasValues(contracts.tools) || hasValues(manifest.commandAliases))
|
|
add("tools");
|
|
if (hasValues(contracts.embeddedExtensionFactories) ||
|
|
hasValues(contracts.agentToolResultMiddleware)) {
|
|
add("runtime");
|
|
}
|
|
if (hasValues(contracts.gatewayMethodDispatch))
|
|
add("gateway");
|
|
if (hasValues(contracts.externalAuthProviders) ||
|
|
hasProperties(manifest.secretProviderIntegrations)) {
|
|
add("security");
|
|
}
|
|
return categories.slice(0, 3);
|
|
}
|
|
export function derivePluginCategoryTags(input) {
|
|
if (input.family === "skill")
|
|
return [];
|
|
return resolvePluginCategories({
|
|
declared: input.categories,
|
|
inferred: input.inferredCategories ?? inferPluginCategoriesFromManifest(input.pluginManifest),
|
|
});
|
|
}
|
|
export function resolveStoredPluginCategories(input) {
|
|
if (input.family === "skill")
|
|
return [];
|
|
try {
|
|
const inferenceCurrent = Boolean(input.latestReleaseId) && input.latestReleaseId === input.inferredFromReleaseId;
|
|
return resolvePluginCategories({
|
|
declared: input.categories,
|
|
inferred: inferenceCurrent ? input.inferredCategories : undefined,
|
|
});
|
|
}
|
|
catch {
|
|
return resolvePluginCategories({});
|
|
}
|
|
}
|
|
//# sourceMappingURL=pluginCategories.js.map
|