diff --git a/ui/src/lib/skills/clawhub-search.ts b/ui/src/lib/skills/clawhub-search.ts new file mode 100644 index 000000000000..9ca44b56c571 --- /dev/null +++ b/ui/src/lib/skills/clawhub-search.ts @@ -0,0 +1,27 @@ +import type { GatewayBrowserClient } from "../../api/gateway.ts"; + +export type ClawHubSearchResult = { + score: number; + slug: string; + displayName: string; + summary?: string; + icon?: string | null; + version?: string; + updatedAt?: number; +}; + +export async function searchClawHub( + client: GatewayBrowserClient, + query: string, + signal?: AbortSignal, +): Promise { + if (!query.trim()) { + return []; + } + const response = await client.request<{ results: ClawHubSearchResult[] }>( + "skills.search", + { query, limit: 20 }, + { signal }, + ); + return response?.results ?? []; +} diff --git a/ui/src/lib/skills/index.test.ts b/ui/src/lib/skills/index.test.ts index 16bd03f627e9..fc1fb7ff595b 100644 --- a/ui/src/lib/skills/index.test.ts +++ b/ui/src/lib/skills/index.test.ts @@ -4,6 +4,7 @@ import { expectDefined } from "@openclaw/normalization-core"; import { describe, expect, it, vi } from "vitest"; import { waitForFast } from "../../test-helpers/wait-for.ts"; import { createRuntimeConfigCapability } from "../config/index.ts"; +import { searchClawHub } from "./clawhub-search.ts"; import { installFromClawHub, installSkill, @@ -13,7 +14,6 @@ import { refreshSkills, reconcileSkillsAgentId, saveSkillApiKey, - searchClawHub, setSkillsAgentId, updateSkillEdit, updateSkillEnabled, diff --git a/ui/src/lib/skills/index.ts b/ui/src/lib/skills/index.ts index 77da72de87e1..5b1df47d754b 100644 --- a/ui/src/lib/skills/index.ts +++ b/ui/src/lib/skills/index.ts @@ -11,6 +11,7 @@ import type { SkillStatusReport, } from "../../api/types.ts"; import { redactToolDetail } from "../browser-redact.ts"; +import type { ClawHubSearchResult } from "./clawhub-search.ts"; import { normalizeSkillApiKeyReplacement, runSkillConfigMutation, @@ -18,16 +19,6 @@ import { type SkillConfigMutationOwner, } from "./config-mutations.ts"; -export type ClawHubSearchResult = { - score: number; - slug: string; - displayName: string; - summary?: string; - icon?: string | null; - version?: string; - updatedAt?: number; -}; - export type ClawHubSkillDetail = { skill: { slug: string; @@ -575,18 +566,33 @@ export async function updateSkillEnabled( enabled: boolean, canDispatch: () => boolean = () => true, ) { - await runSkillMutation(state, skillKey, async (client) => { - const refreshError = await runSkillConfigMutation( - state.runtimeConfig, - client, - { - skillKey, - enabled, - }, - canDispatch, - ); - return skillConfigMutationSuccess(enabled ? "Skill enabled" : "Skill disabled", refreshError); - }); + await runSkillConfigUpdate( + state, + skillKey, + { enabled }, + enabled ? "Skill enabled" : "Skill disabled", + canDispatch, + ); +} + +async function runSkillConfigUpdate( + state: SkillsState, + skillKey: string, + patch: { enabled: boolean } | { apiKey: string }, + message: string, + canDispatch: () => boolean, +) { + await runSkillMutation(state, skillKey, async (client) => + skillConfigMutationSuccess( + message, + await runSkillConfigMutation( + state.runtimeConfig, + client, + { skillKey, ...patch }, + canDispatch, + ), + ), + ); } export async function saveSkillApiKey( @@ -598,21 +604,13 @@ export async function saveSkillApiKey( if (!apiKey) { return; } - await runSkillMutation(state, skillKey, async (client) => { - const refreshError = await runSkillConfigMutation( - state.runtimeConfig, - client, - { - skillKey, - apiKey, - }, - canDispatch, - ); - return skillConfigMutationSuccess( - `API key saved — stored in openclaw.json (skills.entries.${skillKey})`, - refreshError, - ); - }); + await runSkillConfigUpdate( + state, + skillKey, + { apiKey }, + `API key saved — stored in openclaw.json (skills.entries.${skillKey})`, + canDispatch, + ); } export async function installSkill( @@ -637,22 +635,6 @@ export async function installSkill( }); } -export async function searchClawHub( - client: GatewayBrowserClient, - query: string, - signal?: AbortSignal, -): Promise { - if (!query.trim()) { - return []; - } - const response = await client.request<{ results: ClawHubSearchResult[] }>( - "skills.search", - { query, limit: 20 }, - { signal }, - ); - return response?.results ?? []; -} - export async function loadClawHubDetail(state: SkillsState, slug: string) { if (!state.client || !state.connected) { return; diff --git a/ui/src/pages/skills/skills-page.ts b/ui/src/pages/skills/skills-page.ts index 11db828e92ff..5cdbee24ef43 100644 --- a/ui/src/pages/skills/skills-page.ts +++ b/ui/src/pages/skills/skills-page.ts @@ -14,6 +14,7 @@ import { renderHubTabs } from "../../components/hub-tabs.ts"; import { renderSettingsWorkspace } from "../../components/settings-workspace.ts"; import { t } from "../../i18n/index.ts"; import { canCallGatewayMethod } from "../../lib/gateway-methods.ts"; +import { searchClawHub, type ClawHubSearchResult } from "../../lib/skills/clawhub-search.ts"; import { closeClawHubDetail, installFromClawHub, @@ -24,11 +25,9 @@ import { refreshSkills, reconcileSkillsAgentId, saveSkillApiKey, - searchClawHub, setSkillsAgentId, updateSkillEdit, updateSkillEnabled, - type ClawHubSearchResult, type ClawHubSkillDetail, type ClawHubSkillSecurityVerdict, type SkillOperation, diff --git a/ui/src/pages/skills/view.ts b/ui/src/pages/skills/view.ts index 94864e569f4d..0c089175d091 100644 --- a/ui/src/pages/skills/view.ts +++ b/ui/src/pages/skills/view.ts @@ -34,10 +34,10 @@ import { isSkillAvailable, renderSkillStatusChips, } from "../../lib/skills-shared.ts"; +import type { ClawHubSearchResult } from "../../lib/skills/clawhub-search.ts"; import { clawhubVerdictKey, type ClawHubSkillSecurityVerdict, - type ClawHubSearchResult, type ClawHubSkillDetail, type SkillOperation, type SkillMessageMap,