@brianlovin/notion-skills
Version:
Sync agent skills from a Notion database to Claude Code, Codex, OpenCode, Cursor, Gemini CLI.
85 lines • 3.47 kB
JavaScript
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