Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,9 @@ const importBody = (overrides) => ({ podId: POD_ID, name: 'notes', ...overrides

const LEGACY_SOURCE = 'https://github.com/openclaw/skills/tree/main/skills/acme/notes/SKILL.md';
const CLAWHUB_META = 'https://clawhub.ai/api/skill?owner=acme&slug=notes';
const CLAWHUB_ZIP = 'https://clawhub.ai/api/v1/download?slug=notes&version=1.2.0';
const SOURCE_MISSING = 'This skill is no longer published at its source.';
const CLAWHUB_ZIP = 'https://clawhub.ai/api/v1/download?slug=notes&ownerHandle=acme&version=1.2.0';
const SOURCE_MISSING = 'This skill is unavailable from its listed publisher. '
+ 'Choose another skill or ask the publisher for an updated source.';
const SOURCE_UNREACHABLE = "Couldn't reach this skill's source. Try again in a few minutes.";

const zipOf = (files) => {
Expand Down
3 changes: 2 additions & 1 deletion backend/routes/skills.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ const { isOutboundUrlRefused } = require('../services/outboundUrlGuard');
const SOURCE_URL_REFUSED = 'Skill source URL must be an https link on github.com or raw.githubusercontent.com.';
// A skill's source not having it is not our server failing (#2189): a 404 when
// the source answered without the skill, a 502 when it could not be read.
const SOURCE_MISSING = 'This skill is no longer published at its source.';
const SOURCE_MISSING = 'This skill is unavailable from its listed publisher. '
+ 'Choose another skill or ask the publisher for an updated source.';
const SOURCE_UNREACHABLE = "Couldn't reach this skill's source. Try again in a few minutes.";
const sourceUnavailableReply = (res: Res, error: { missing: boolean; message: string }, what: string) => {
console.warn(`[skills] ${what} source unavailable:`, error.message);
Expand Down
10 changes: 5 additions & 5 deletions backend/services/skillsCatalogService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -332,7 +332,8 @@ export const fetchSkillDirectoryFiles = async (sourceUrl: string, options: Fetch
// repo went 404 in early May 2026, but the same skills are served by ClawHub
// at canonical URLs:
// GET /api/skill?owner=<owner>&slug=<slug> → metadata JSON (incl. latestVersion.version)
// GET /api/v1/download?slug=<slug>&version=<v> → ZIP bundle (SKILL.md + sub-files)
// GET /api/v1/download?slug=<slug>&ownerHandle=<owner>&version=<v>
// → ZIP bundle (SKILL.md + sub-files)
//
// We use this both to recover dead catalog entries (presetSkillsAutoImport
// rewrites openclaw/skills URLs to ClawHub fetches) and for any future
Expand Down Expand Up @@ -372,9 +373,8 @@ export const parseLegacyOpenclawSkillsUrl = (sourceUrl: string): { owner: string
* Resolve and download a skill from ClawHub. Returns the SKILL.md content +
* any sub-files (sub-skills, references/, scripts/) up to size budgets.
*
* Note: the metadata endpoint requires `owner` to be passed; the download
* endpoint only takes `slug` (slugs appear to be globally unique). If two
* authors publish the same slug ClawHub presumably disambiguates server-side.
* Both calls must retain the catalog publisher. ClawHub returns 409 for a
* download by slug alone when multiple publishers use that slug.
*/
export const fetchSkillBundleFromClawHub = async (
owner: string,
Expand Down Expand Up @@ -412,7 +412,7 @@ export const fetchSkillBundleFromClawHub = async (
let buf: Buffer;
try {
const dlResp = await fetchBytesFromAllowedHost(
`${CLAWHUB_BASE}/api/v1/download?slug=${safeSlug}&version=${encodeURIComponent(version)}`,
`${CLAWHUB_BASE}/api/v1/download?slug=${safeSlug}&ownerHandle=${safeOwner}&version=${encodeURIComponent(version)}`,
{ allowedOrigins: CLAWHUB_ORIGINS, maxBytes: CLAWHUB_MAX_ZIP_BYTES },
);
if (!dlResp.ok) throw unavailableForStatus('ClawHub download', dlResp.status);
Expand Down
Loading