import { searchSkillsSh, getPopularSkillsSh, previewSkillsSh, fetchSkillFiles, assertSafeSkillName, assertSafeFilePath } from './chunk-753JFAF2.js';
import { getCallerAuthorId } from './chunk-SXZS6VZ3.js';
import { skillsShSearchResponseSchema, skillsShListResponseSchema, skillsShPreviewResponseSchema } from './chunk-ZHULRNJG.js';
import { toSlug } from './chunk-QIQWHDPH.js';
import { handleError } from './chunk-7ZWJX3AN.js';
import { createRoute } from './chunk-PIKPS6Q6.js';
import { HTTPException } from './chunk-6QWQZI4Q.js';
import { z } from 'zod/v4';

var builderRegistryEntrySchema = z.object({
  id: z.literal("skills-sh").describe("Stable registry identifier"),
  enabled: z.boolean().describe("Whether this registry is enabled in the running deployment"),
  label: z.string().describe("Human-readable registry name")
});
var builderRegistriesResponseSchema = z.object({
  registries: z.array(builderRegistryEntrySchema)
});
var builderRegistryPathParams = z.object({
  registryId: z.string().describe('Registry identifier (e.g. "skills-sh")')
});
var builderRegistrySearchQuerySchema = z.object({
  q: z.string().describe("Search query"),
  limit: z.coerce.number().int().min(1).max(100).optional().default(10).describe("Maximum number of results (1-100)")
});
var builderRegistryPopularQuerySchema = z.object({
  limit: z.coerce.number().int().min(1).max(100).optional().default(10).describe("Maximum number of results (1-100)"),
  offset: z.coerce.number().int().min(0).optional().default(0).describe("Offset for pagination (must be a multiple of `limit`)")
}).refine((args) => args.offset % args.limit === 0, {
  message: "offset must be a multiple of limit (the upstream registry pages by `limit`)",
  path: ["offset"]
});
var builderRegistryPreviewQuerySchema = z.object({
  owner: z.string().describe("GitHub repository owner"),
  repo: z.string().describe("GitHub repository name"),
  path: z.string().describe("Skill name within repo")
});
var builderRegistryInstallBodySchema = z.object({
  owner: z.string().describe("GitHub repository owner"),
  repo: z.string().describe("GitHub repository name"),
  skillName: z.string().describe("Skill name from the registry"),
  visibility: z.enum(["private", "public"]).optional().describe("Visibility for the new stored skill")
});
var builderRegistryInstallResponseSchema = z.object({
  storedSkillId: z.string().describe("Id of the newly created stored skill"),
  name: z.string().describe("Resolved skill name"),
  filesWritten: z.number().describe("Number of files materialized into the skill version snapshot")
});

// src/server/handlers/builder-registry.ts
var REGISTRY_LABELS = {
  "skills-sh": "skills.sh"
};
async function resolveRegistries(mastra) {
  const editor = mastra.getEditor();
  if (!editor || typeof editor.resolveBuilder !== "function") {
    return [{ id: "skills-sh", enabled: false, label: REGISTRY_LABELS["skills-sh"] }];
  }
  const builder = await editor.resolveBuilder();
  const registries = builder?.getRegistries?.();
  return [
    {
      id: "skills-sh",
      enabled: registries?.skillsSh?.enabled === true,
      label: REGISTRY_LABELS["skills-sh"]
    }
  ];
}
async function requireEnabledRegistry(mastra, registryId) {
  const list = await resolveRegistries(mastra);
  const match = list.find((r) => r.id === registryId);
  if (!match || !match.enabled) {
    throw new HTTPException(404, { message: "Registry not found" });
  }
}
function buildFileTree(files) {
  const root = [];
  for (const file of files) {
    const safePath = assertSafeFilePath(file.path);
    const segments = safePath.split("/").filter(Boolean);
    if (segments.length === 0) continue;
    let cursor = root;
    for (let i = 0; i < segments.length - 1; i++) {
      const segment = segments[i];
      let folder = cursor.find((node) => node.type === "folder" && node.name === segment);
      if (!folder) {
        folder = { name: segment, type: "folder", children: [] };
        cursor.push(folder);
      }
      if (!folder.children) folder.children = [];
      cursor = folder.children;
    }
    const fileName = segments[segments.length - 1];
    const content = file.encoding === "base64" ? Buffer.from(file.content, "base64").toString("utf-8") : file.content;
    cursor.push({ name: fileName, type: "file", content });
  }
  return root;
}
function parseSkillSnapshot(files) {
  const skillMd = files.find((f) => f.path === "SKILL.md");
  if (!skillMd) return null;
  const raw = skillMd.encoding === "base64" ? Buffer.from(skillMd.content, "base64").toString("utf-8") : skillMd.content;
  const fmMatch = raw.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/);
  if (!fmMatch) {
    return { instructions: raw.trim() };
  }
  const fmBlock = fmMatch[1] ?? "";
  const body = fmMatch[2] ?? "";
  const frontmatter = {};
  for (const line of fmBlock.split(/\r?\n/)) {
    const m = line.match(/^([A-Za-z0-9_-]+)\s*:\s*(.*)$/);
    if (!m) continue;
    const key = m[1];
    const value = m[2] ?? "";
    if (!key) continue;
    frontmatter[key] = value.trim().replace(/^["'](.*)["']$/, "$1");
  }
  return {
    name: frontmatter.name,
    description: frontmatter.description,
    instructions: body.trim()
  };
}
var LIST_BUILDER_REGISTRIES_ROUTE = createRoute({
  method: "GET",
  path: "/editor/builder/registries",
  responseType: "json",
  responseSchema: builderRegistriesResponseSchema,
  summary: "List available skill registries",
  description: "Returns the configured external skill registries and their enabled state.",
  tags: ["Editor"],
  requiresAuth: true,
  requiresPermission: "stored-skills:read",
  handler: async ({ mastra }) => {
    try {
      const registries = await resolveRegistries(mastra);
      return { registries };
    } catch (error) {
      return handleError(error, "Error listing builder registries");
    }
  }
});
var BUILDER_REGISTRY_SEARCH_ROUTE = createRoute({
  method: "GET",
  path: "/editor/builder/registries/:registryId/search",
  responseType: "json",
  pathParamSchema: builderRegistryPathParams,
  queryParamSchema: builderRegistrySearchQuerySchema,
  responseSchema: skillsShSearchResponseSchema,
  summary: "Search skills in a registry",
  description: "Proxies a search request to the configured registry to avoid CORS issues.",
  tags: ["Editor", "Skills"],
  requiresAuth: true,
  requiresPermission: "stored-skills:read",
  handler: async ({ mastra, registryId, q, limit }) => {
    try {
      await requireEnabledRegistry(mastra, registryId);
      return await searchSkillsSh({ q, limit });
    } catch (error) {
      if (error instanceof HTTPException) throw error;
      return handleError(error, "Error searching registry");
    }
  }
});
var BUILDER_REGISTRY_POPULAR_ROUTE = createRoute({
  method: "GET",
  path: "/editor/builder/registries/:registryId/popular",
  responseType: "json",
  pathParamSchema: builderRegistryPathParams,
  queryParamSchema: builderRegistryPopularQuerySchema,
  responseSchema: skillsShListResponseSchema,
  summary: "Get popular skills from a registry",
  description: "Proxies a popular-skills request to the configured registry to avoid CORS issues.",
  tags: ["Editor", "Skills"],
  requiresAuth: true,
  requiresPermission: "stored-skills:read",
  handler: async ({ mastra, registryId, limit, offset }) => {
    try {
      await requireEnabledRegistry(mastra, registryId);
      return await getPopularSkillsSh({ limit, offset });
    } catch (error) {
      if (error instanceof HTTPException) throw error;
      return handleError(error, "Error fetching popular skills");
    }
  }
});
var BUILDER_REGISTRY_PREVIEW_ROUTE = createRoute({
  method: "GET",
  path: "/editor/builder/registries/:registryId/preview",
  responseType: "json",
  pathParamSchema: builderRegistryPathParams,
  queryParamSchema: builderRegistryPreviewQuerySchema,
  responseSchema: skillsShPreviewResponseSchema,
  summary: "Preview a skill from a registry",
  description: "Fetches the SKILL.md content for a single skill in the configured registry.",
  tags: ["Editor", "Skills"],
  requiresAuth: true,
  requiresPermission: "stored-skills:read",
  handler: async ({ mastra, registryId, owner, repo, path: skillName }) => {
    try {
      await requireEnabledRegistry(mastra, registryId);
      return await previewSkillsSh({ owner, repo, skillName });
    } catch (error) {
      if (error instanceof HTTPException) throw error;
      return handleError(error, "Error fetching skill preview");
    }
  }
});
var BUILDER_REGISTRY_INSTALL_ROUTE = createRoute({
  method: "POST",
  path: "/editor/builder/registries/:registryId/install",
  responseType: "json",
  pathParamSchema: builderRegistryPathParams,
  bodySchema: builderRegistryInstallBodySchema,
  responseSchema: builderRegistryInstallResponseSchema,
  summary: "Install a registry skill into stored skills",
  description: "Fetches a skill from the configured registry and persists it as a new stored skill.",
  tags: ["Editor", "Skills"],
  requiresAuth: true,
  requiresPermission: "stored-skills:write",
  handler: async ({ mastra, requestContext, registryId, owner, repo, skillName, visibility: bodyVisibility }) => {
    try {
      await requireEnabledRegistry(mastra, registryId);
      const storage = mastra.getStorage();
      if (!storage) {
        throw new HTTPException(500, { message: "Storage is not configured" });
      }
      const skillStore = await storage.getStore("skills");
      if (!skillStore) {
        throw new HTTPException(500, { message: "Skills storage domain is not available" });
      }
      const result = await fetchSkillFiles(owner, repo, skillName);
      if (!result || result.files.length === 0) {
        throw new HTTPException(404, {
          message: `Could not find skill "${skillName}" in ${owner}/${repo}.`
        });
      }
      const safeSkillId = assertSafeSkillName(result.skillId);
      const files = buildFileTree(result.files);
      const snapshot = parseSkillSnapshot(result.files);
      const resolvedName = snapshot?.name ?? safeSkillId;
      const description = snapshot?.description ?? `Imported from ${owner}/${repo}`;
      const id = toSlug(resolvedName) || safeSkillId;
      if (!id) {
        throw new HTTPException(400, {
          message: "Could not derive skill ID from registry skill metadata."
        });
      }
      const existing = await skillStore.getById(id);
      if (existing) {
        throw new HTTPException(409, {
          message: `Skill with id "${id}" already exists.`,
          // Surface the existing id so the client can deep-link.
          cause: { storedSkillId: id }
        });
      }
      const authorId = getCallerAuthorId(requestContext) ?? void 0;
      const visibility = authorId ? bodyVisibility ?? "private" : "public";
      const instructions = snapshot?.instructions?.trim() ? snapshot.instructions : description;
      await skillStore.create({
        skill: {
          id,
          authorId,
          visibility,
          name: resolvedName,
          description,
          instructions,
          files,
          metadata: {
            origin: {
              type: "skills-sh",
              owner,
              repo,
              skillName
            }
          }
        }
      });
      return {
        storedSkillId: id,
        name: resolvedName,
        filesWritten: result.files.length
      };
    } catch (error) {
      if (error instanceof HTTPException) throw error;
      return handleError(error, "Error installing registry skill");
    }
  }
});

export { BUILDER_REGISTRY_INSTALL_ROUTE, BUILDER_REGISTRY_POPULAR_ROUTE, BUILDER_REGISTRY_PREVIEW_ROUTE, BUILDER_REGISTRY_SEARCH_ROUTE, LIST_BUILDER_REGISTRIES_ROUTE };
//# sourceMappingURL=chunk-ERCBJA5A.js.map
//# sourceMappingURL=chunk-ERCBJA5A.js.map