diff --git a/src/model-catalog/provider-index/normalize.test.ts b/src/model-catalog/provider-index/normalize.test.ts index ae39507058c..bf87be4ef0f 100644 --- a/src/model-catalog/provider-index/normalize.test.ts +++ b/src/model-catalog/provider-index/normalize.test.ts @@ -13,8 +13,9 @@ describe("OpenClaw provider index", () => { id: "moonshot", package: " @openclaw/plugin-moonshot ", install: { + clawhubSpec: " clawhub:openclaw/moonshot@2026.5.2 ", npmSpec: " @openclaw/plugin-moonshot@1.2.3 ", - defaultChoice: "npm", + defaultChoice: "clawhub", expectedIntegrity: " sha512-moonshot ", }, }, @@ -63,8 +64,9 @@ describe("OpenClaw provider index", () => { id: "moonshot", package: "@openclaw/plugin-moonshot", install: { + clawhubSpec: "clawhub:openclaw/moonshot@2026.5.2", npmSpec: "@openclaw/plugin-moonshot@1.2.3", - defaultChoice: "npm", + defaultChoice: "clawhub", expectedIntegrity: "sha512-moonshot", }, }, diff --git a/src/model-catalog/provider-index/normalize.ts b/src/model-catalog/provider-index/normalize.ts index 956a9b4ceea..a0f29f32b5c 100644 --- a/src/model-catalog/provider-index/normalize.ts +++ b/src/model-catalog/provider-index/normalize.ts @@ -1,3 +1,4 @@ +import { parseClawHubPluginSpec } from "../../infra/clawhub-spec.js"; import { parseRegistryNpmSpec } from "../../infra/npm-registry-spec.js"; import { isBlockedObjectKey } from "../../infra/prototype-keys.js"; import { normalizeOptionalString } from "../../shared/string-coerce.js"; @@ -25,16 +26,24 @@ function normalizeInstall(value: unknown): OpenClawProviderIndexPluginInstall | if (!isRecord(value)) { return undefined; } + const clawhubSpec = normalizeOptionalString(value.clawhubSpec); + const parsedClawHub = clawhubSpec ? parseClawHubPluginSpec(clawhubSpec) : null; const npmSpec = normalizeOptionalString(value.npmSpec); - const parsed = npmSpec ? parseRegistryNpmSpec(npmSpec) : null; - if (!parsed) { + const parsedNpm = npmSpec ? parseRegistryNpmSpec(npmSpec) : null; + if (!parsedClawHub && !parsedNpm) { return undefined; } - const defaultChoice = value.defaultChoice === "npm" ? "npm" : undefined; + const defaultChoice = + value.defaultChoice === "clawhub" && parsedClawHub + ? "clawhub" + : value.defaultChoice === "npm" && parsedNpm + ? "npm" + : undefined; const minHostVersion = normalizeOptionalString(value.minHostVersion); const expectedIntegrity = normalizeOptionalString(value.expectedIntegrity); return { - npmSpec: parsed.raw, + ...(parsedClawHub ? { clawhubSpec } : {}), + ...(parsedNpm ? { npmSpec: parsedNpm.raw } : {}), ...(defaultChoice ? { defaultChoice } : {}), ...(minHostVersion ? { minHostVersion } : {}), ...(expectedIntegrity ? { expectedIntegrity } : {}), diff --git a/src/model-catalog/provider-index/types.ts b/src/model-catalog/provider-index/types.ts index 18f1f84d174..0529afcea1a 100644 --- a/src/model-catalog/provider-index/types.ts +++ b/src/model-catalog/provider-index/types.ts @@ -1,8 +1,9 @@ import type { ModelCatalogProvider } from "../types.js"; export type OpenClawProviderIndexPluginInstall = { - npmSpec: string; - defaultChoice?: "npm"; + clawhubSpec?: string; + npmSpec?: string; + defaultChoice?: "clawhub" | "npm"; minHostVersion?: string; expectedIntegrity?: string; };