UNPKG

@brianlovin/notion-skills

Version:

Sync agent skills from a Notion database to Claude Code, Codex, OpenCode, Cursor, Gemini CLI.

85 lines 3.47 kB
import { findByKey, parseSkillRef, formatRef } from "./sources.js"; export function resolveInstalledRef(input, sources, manifest) { const { sourceKey, slug } = parseSkillRef(input); if (sourceKey !== undefined) { const source = findByKey(sources, sourceKey); if (!source) return { ok: false, reason: "unknown_source", key: sourceKey }; for (const [localSlug, entry] of Object.entries(manifest.skills)) { if (entry.source_key === sourceKey && entry.source_slug === slug) { return { ok: true, localSlug, entry, source }; } } return { ok: false, reason: "not_found" }; } // Bare input: local_slug exact match wins. const direct = manifest.skills[input]; if (direct) { const source = findByKey(sources, direct.source_key); if (!source) return { ok: false, reason: "unknown_source", key: direct.source_key }; return { ok: true, localSlug: input, entry: direct, source }; } // Otherwise scan source_slug across all sources. const matches = []; for (const [localSlug, entry] of Object.entries(manifest.skills)) { if (entry.source_slug === input) matches.push({ localSlug, entry }); } if (matches.length === 0) return { ok: false, reason: "not_found" }; if (matches.length === 1) { const m = matches[0]; const source = findByKey(sources, m.entry.source_key); if (!source) return { ok: false, reason: "unknown_source", key: m.entry.source_key }; return { ok: true, localSlug: m.localSlug, entry: m.entry, source }; } return { ok: false, reason: "ambiguous", matches: matches.map((m) => formatRef(m.entry.source_key, m.entry.source_slug)), }; } /** * Pick a non-colliding local_slug for a freshly-installed skill from a * source. Default = source_slug; if that's already taken on disk, * auto-namespace as `<source-key>-<slug>`. If THAT also collides, * append numeric suffix (-2, -3, ...). * * Returns: * - `{ slug: <chosen>, autoNamespaced: false }` when the source slug * was free * - `{ slug: <chosen>, autoNamespaced: true }` when collision forced * a prefix or numeric suffix * * A pure helper — caller decides whether to print a warning. */ export function chooseLocalSlug(sourceKey, sourceSlug, manifest, override) { if (override) { if (manifest.skills[override]) { // Override collides too — keep going. Caller is expected to have // already validated this won't happen, but be defensive. return appendUntilFree(override, manifest); } return { slug: override, autoNamespaced: false }; } if (!manifest.skills[sourceSlug]) { return { slug: sourceSlug, autoNamespaced: false }; } const namespaced = `${sourceKey}-${sourceSlug}`; if (!manifest.skills[namespaced]) { return { slug: namespaced, autoNamespaced: true }; } return appendUntilFree(namespaced, manifest, true); } function appendUntilFree(base, manifest, autoNamespaced = false) { for (let i = 2; i < 1000; i++) { const candidate = `${base}-${i}`; if (!manifest.skills[candidate]) { return { slug: candidate, autoNamespaced }; } } return { slug: `${base}-${Date.now().toString(36)}`, autoNamespaced }; } //# sourceMappingURL=resolvers.js.map